Python
responder

モダンでフレンドリーな Responder入門 と調べても中々出てこない情報達

ResponderとはRequestsやpipenvの作者であるkennethreitz氏によるモダンなwebフレームワークです。

FlaskとFalconの良い部分を合わせるというのがアイデアのようで、確かに多くの機能を受け継いでいます。

さて、では初めて行きましょう。


基礎

まずは、Responder.APIを宣言するところから始めます。

import responder

api = responder.API()

インスタンス名はFlaskのようなappではなくapiとするのがマナー(?)のようです。


ルーティング

ルートを定義するには、@api.route("route_name")で関数をデコレートするか、api.add_route("route_name", callback)で関数をcallbackとして与えることができます。

基本的にはデコレートするほうがわかりやすいと思います。

ファイルが大きくなってきて、ルートを別ファイルに記述するようなときは、callbackとして与える方法ももちろん良いでしょう。

@api.route("/main_page")

def main_page(req, resp):
resp.text= "Thanks for accessing" #------------- text
resp.media = {"success": True} #---------------- json, yaml
resp.html = "<p>Thanks for accessing</p>" #----- html
resp.status_code = 200 #------------------------ http status
resp.headers["X-Pizza"] = "42" #---------------- header

このように、respにデータを与えることでレスポンスを操作します。

基本的にresp.status_codeは設定しなければ自動で200となります。ですので、必要な情報のみ与えてください。

また、ルーティングには、f文字列式の動的ルーティングを使うことができます。

@api.route("/main_page/{name}")

def main_page(req, resp, *, name):
resp.text= f"Thanks for accessing, {name}"

callbackにはキーワード引数で与えられるので、上記のようにしてください。


非同期・バックグラウンド実行

await, async, @api.background.taskを用いることで、バックグラウンドで処理を実行することができます。

@api.route("/taking")

async def some_function(req, resp):

@api.background.task
def take_long_time():
# 時間のかかる処理

take_long_time()

resp.media = {'success': True}


実行

api.run()を実行してください。

if __name__ == '__main__':

api.run()


なかなか出てこない情報達


port, address, デバッグモードの変え方

api.run()の引数に値を与えてください。

api.run(port=8080, address="127.0.0.2", debug=True)

そのほかにも、デバッグレベルなど沢山の引数を取ります。それらは、uvicornのsettingをご覧ください。


リクエストのメソッド確認

req.methodを見てください。

@api.route("/check_method")

def check_method(req, resp):
if req.method == "get":
resp.text = "this is get"
elif req.method == "post":
resp.text = "this is post"


postデータの受け取り方

await req.media()をasyncで定義したコルーチンの中で呼び出してください。

@api.route("/take_post")

async def take_post(req, resp):
if req.method == "get":
resp.text = "please send post"
else:
data = await req.media()
resp.media = data
resp.text = "I'm giving you back :) "

req.media()の引数にformat="form"format="json"のように指定することで、受け取るものを選ぶことができます。


Cookieに値を設定する、取得する

api.sessionreq.cookiesで取得、api.sessionresp.cookiesで設定。細かく設定するにはresp.set_cookieを使用しましょう。

api.sessionreq.cookiesapi.sessionは辞書で提供されるので、簡単に取得、設定することができます。

resp.set_cookieでは、以下の値を引数に取ります。



  • key : cookieの名前です


  • value : 実際に保存するデータです


  • expires : この cookie が破棄される日付です


  • max_age : この cookie が破棄されるまでの秒数です


  • secure : https のみで利用できるよう制限するかです


  • httponly : http の内部から(javascriptなどを利用して)閲覧できないよう制限するかです


Login Management

ResponderにはFlask-loginのようなログインマネージャは存在しません。

ですから、作りました。(隠しきれないステマ)

Responder-Login --- Docs

下記のように使用できます。

import responder

from responder_login import LoginManager, UserMixin

api = responder.API()
lm = LoginManager(api)

users = []

class User(UserMixin):
id = None
name = "Anonymous"
age = 0

def __init__(self, name, age):
global users
self.name = name
self.age = age
users.append(self)
self.id = users.index(self)

def get_id(self):
return self.id

@lm.user_loader
def user_loader(user_id):
try:
return users[int(user_id)]
except IndexError:
return None

@api.route("/login/{name}/{age}")
@lm.login_prohibited
def login(req, resp, *, name, age):
user = User(name, age)
lm.login_user(user)
resp.text = f"you've logged in as User; name: {user.name}, age: {user.age}"

@api.route("/show")
def show(req, resp):
user = lm.current_user
if user.is_authenticated:
resp.text = f"you're logging in as User; name: {user.name}, age: {user.age}"
else:
resp.text = "you're not logging in"

@api.route("/logout")
@lm.login_required
def logout(req, resp):
lm.logout_user()
resp.text = "you've logged out"

if __name__ == "__main__":
api.run()

ガバガバ英語と少ない機能、不適な実装だらけですので、プルリクを沢山送って、issueを沢山立ててもらえると嬉しいです。