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.session
・req.cookies
で取得、api.session
・resp.cookies
で設定。細かく設定するにはresp.set_cookie
を使用しましょう。
api.session
・req.cookies
・api.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を沢山立ててもらえると嬉しいです。