この記事は Python のモダンな Web フレームワークである「Responder」の入門チュートリアルです。
公式のチュートリアル「Quick Start!」に沿って進めていきます。
この記事のサンプルコードは GitHub で公開していますので、参考にしてください。
https://github.com/nskydiving/responder_quick_start
Responder とは
Responder は Requests や Pipenv の開発者として知られる Kenneth Reitz 氏 によって開発された Web フレームワークです。
Responder のコンセプトは、人気の Web フレームワークである Flask と Falcon の両方から良い部分を取り入れ、さらに Kenneth Reitz 氏の持つ新しいアイデアを加えることで、新しい一つのWeb フレームワークに統合することです。
さらに詳しい情報を知りたい方は、以下のブログを参考にしてください。
人間のためのイケてるPython WebFramework「responder」、そして作者のKenneth Reitzについて
https://blog.ikedaosushi.com/entry/2018/12/01/195512
Responder の特徴
- 単一のインポート文で使える API
- 継承のないクラスベースのビュー
- ASGI
- 他の ASGI / WSGI アプリケーションをマウント可能
- f-strings 構文によるルート宣言
- 変更可能なレスポンスオブジェクトがビューに渡されます。何も return する必要はありません。
- ThreadPoolExecutor によるバックグラウンドタスク
- GraphiQL による GraphQL
- OpenAPI スキーマの生成
- SPA(シングルページアプリケーション)
動作環境
- Mac OS X 10.12.6
- Pipenv 2018.11.26
- Python 3.6.7
- Responder 1.1.2
環境構築
Mac のターミナルを開いて、必要なソフトウェアをインストールします。
Pipenv のインストール
最初に Pipenv をインストールします。
Pipenv は Python の仮想環境を構築するためのツールです。
$ brew install pipenv
Python のインストール
適当な作業ディレクトリを作成し、Python 環境を構築します。
Python はバージョン 3.6.0 以上が必須となるので注意してください。
$ mkdir work
$ cd work
$ pipenv install --python 3.6.7
Responder のインストール
最後に Responder をインストールします。
$ pipenv install responder --pre
Hello World!
準備が整ったら、お決まりの「Hello World!」を書いてみましょう!
「hello_world.py」という名前でファイルを作成し、以下のコードを記述してください。
import responder
api = responder.API()
@api.route("/")
def hello_world(req, resp):
resp.text = "hello, world!"
if __name__ == '__main__':
api.run()
このコードを実行します。
$ python hello_world.py
うまくいけば Responder アプリケーションが起動し、以下のようなメッセージが表示されます。
INFO: Started server process [50733]
INFO: Waiting for application startup.
INFO: Uvicorn running on http://127.0.0.1:5042 (Press CTRL+C to quit)
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/
「hello, world!」という文字列が表示されれば成功です!
※「ModuleNotFoundError: No module named 'starlette.lifespan'」エラーが出る場合は?
この問題を回避するために、以下のコマンドを実行してください。
$ pipenv install starlette==0.8
この問題の詳細は GitHub の issues を参照してください。
https://github.com/kennethreitz/responder/issues/255
引数を受け取る
以下のコードを記述して、Responder アプリケーションを起動してください。
import responder
api = responder.API()
@api.route("/hello/{who}")
def hello_to(req, resp, *, who):
resp.text = f"hello, {who}!"
if __name__ == '__main__':
api.run()
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/hello/brettcannon
引数「brettcannon」が Responder アプリケーションへ渡され、「hello, brettcannon!」と表示されます。
JSON / YAML を返す
以下のコードを記述して、Responder アプリケーションを起動してください。
import responder
api = responder.API()
@api.route("/hello/{who}/json")
def hello_to(req, resp, *, who):
resp.media = {"hello": who}
if __name__ == '__main__':
api.run()
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/hello/guido/json
JSON 形式のデータ「{"hello": "guido"}」がブラウザに表示されます。
テンプレートを描画する
以下のコードを記述してください。
import responder
api = responder.API()
@api.route("/hello/{who}/html")
def hello_html(req, resp, *, who):
resp.content = api.template('hello.html', who=who)
if __name__ == '__main__':
api.run()
次にサブディレクトリ「template」の配下にテンプレートファイル「hello.html」を作成し、以下のコードを記述してください。
Hello, {{ who }}
「rendering_a_template.py」と「templates/hello.html」が作成できたら、Responder アプリケーションを起動してください。
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/hello/guido/html
テンプレートファイル「templates/hello.html」に名前「guido」が渡され、「Hello, guido」と表示されます。
Responder では、テンプレートエンジン「Jinja2」が使えます。
Responder は Jinja2 を内包しているので、インストールどころかインポートすら必要ありません。
レスポンスのステータスコードを設定する
以下のコードを記述して、Responder アプリケーションを起動してください。
import responder
api = responder.API()
@api.route("/416")
def teapot(req, resp)
resp.status_code = api.status_codes.HTTP_416 # ...or 416
if __name__ == '__main__':
api.run()
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/416
ステータスコード「416」が返されます。
ステータスコードは Chrome のデベロッパーツール「Network > Status」で確認することができます。
レスポンスのヘッダ情報を設定する
以下のコードを記述して、Responder アプリケーションを起動してください。
import responder
api = responder.API()
@api.route("/pizza")
def pizza_pizza(req, resp):
resp.headers['X-Pizza'] = '42'
if __name__ == '__main__':
api.run()
ブラウザを開いて、以下の URL にアクセスしてみましょう。
http://127.0.0.1:5042/pizza
ヘッダ情報「X-Pizza」に「42」が設定されます。
ヘッダ情報は Chrome のデベロッパーツール「Network > Name(pizza)」をクリックして確認することができます。
データの受け取りとバックグラウンドタスク
以下のコードを記述して、Responder アプリケーションを起動してください。
import responder
import time
api = responder.API()
@api.route("/incoming")
async def receive_incoming(req, resp):
@api.background.task
def process_data(data):
"""Just sleeps for three seconds, as a demo."""
time.sleep(3)
# Parse the incoming data as form-encoded.
# Note: 'json' and 'yaml' formats are also automatically supported.
data = await req.media()
# Process the data (in the background).
process_data(data)
# Immediately respond that upload was successful.
resp.media = {'success': True}
if __name__ == '__main__':
api.run()
curl を使って Responder アプリケーションへ JSON データを送信します。
$ curl http://127.0.0.1:5042/incoming -X POST -H "Content-Type: application/json" -d '{"key": "value"}'
Responder アプリケーションは、データの受け取り処理で 3 秒のスリープを行なっていますが、この処理はバックグラウンドで処理されるため、即座にレスポンス「{'success': true}」が返されます。
さいごに
Responder は 2018 年 10 月に公開されたばかりの新しい Web フレームワークですが、GitHub のスターはすでに 2000 を超えています。
Responder がここまで支持されている理由として、モダンな機能を搭載し、Flask の進化版のような立ち位置にあること、さらに有名モジュールの作者によって開発されていることが大きいように思います。
まだ少しさわった程度ですが、将来有望な Web フレームワークであると感じています。
Responder のことをもっと知りたいという方は、Responder の公式サイト を読んでください。