Edited at

はじめての Responder(Python の次世代 Web フレームワーク)

この記事は Python のモダンな Web フレームワークである「Responder」の入門チュートリアルです。

公式のチュートリアル「Quick Start!」に沿って進めていきます。

この記事のサンプルコードは GitHub で公開していますので、参考にしてください。

https://github.com/nskydiving/responder_quick_start


Responder とは

ResponderRequestsPipenv の開発者として知られる Kenneth Reitz 氏 によって開発された Web フレームワークです。

Responder のコンセプトは、人気の Web フレームワークである FlaskFalcon の両方から良い部分を取り入れ、さらに 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」という名前でファイルを作成し、以下のコードを記述してください。


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 アプリケーションを起動してください。


accept_route_arguments.py

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 アプリケーションを起動してください。


returning_json_yaml.py

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"}」がブラウザに表示されます。


テンプレートを描画する

以下のコードを記述してください。


rendering_a_template.py

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」を作成し、以下のコードを記述してください。


templates/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 アプリケーションを起動してください。


setting_response_status_code.py

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 アプリケーションを起動してください。


setting_response_headers.py

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 アプリケーションを起動してください。


setting_response_headers.py

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 の公式サイト を読んでください。