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

この記事は Python のモダンな Web フレームワークである「[Responder](https://python-responder.org/en/latest/)」の入門チュートリアルです。

公式のチュートリアル「[Quick Start!](https://python-responder.org/en/latest/quickstart.html)」に沿って進めていきます。

この記事のサンプルコードは GitHub で公開していますので、参考にしてください。
https://github.com/nskydiving/responder_quick_start

## Responder とは
**Responder** は [Requests](http://docs.python-requests.org/en/master/) や [Pipenv](https://github.com/pypa/pipenv) の開発者として知られる [Kenneth Reitz 氏](https://twitter.com/kennethreitz) によって開発された Web フレームワークです。

Responder のコンセプトは、人気の Web フレームワークである [Flask](http://flask.pocoo.org/) と [Falcon](https://falcon.readthedocs.io/en/stable/) の両方から良い部分を取り入れ、さらに Kenneth Reitz 氏の持つ新しいアイデアを加えることで、新しい一つのWeb フレームワークに統合することです。

さらに詳しい情報を知りたい方は、以下のブログを参考にしてください。

**人間のためのイケてるPython WebFramework「responder」、そして作者のKenneth Reitzについて**
https://blog.ikedaosushi.com/entry/2018/12/01/195512

## Responder の特徴

- 単一のインポート文で使える API
- 継承のないクラスベースのビュー
- [ASGI](https://channels.readthedocs.io/en/latest/asgi.html) 
- 他の ASGI / WSGI アプリケーションをマウント可能
- f-strings 構文によるルート宣言
- 変更可能なレスポンスオブジェクトがビューに渡されます。何も return する必要はありません。
- [ThreadPoolExecutor](https://docs.python.jp/3/library/concurrent.futures.html) によるバックグラウンドタスク
- [GraphiQL](https://github.com/graphql/graphiql) による [GraphQL](https://graphql.org/) 
- OpenAPI スキーマの生成
- SPA（シングルページアプリケーション）

## 動作環境
- Mac OS X 10.12.6
- Pipenv 2018.11.26
- Python 3.6.7
- Responder 1.1.2

## 環境構築
Mac のターミナルを開いて、必要なソフトウェアをインストールします。

#### Pipenv のインストール
最初に [Pipenv](https://github.com/pypa/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](http://jinja.pocoo.org/docs/2.10/#welcome-to-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 アプリケーションは、データの受け取り処理で ３ 秒のスリープを行なっていますが、この処理はバックグラウンドで処理されるため、即座にレスポンス「{'success': true}」が返されます。

## さいごに
**Responder** は 2018 年 10 月に公開されたばかりの新しい Web フレームワークですが、GitHub のスターはすでに 2000 を超えています。

Responder がここまで支持されている理由として、モダンな機能を搭載し、Flask の進化版のような立ち位置にあること、さらに有名モジュールの作者によって開発されていることが大きいように思います。

まだ少しさわった程度ですが、将来有望な Web フレームワークであると感じています。

Responder のことをもっと知りたいという方は、[Responder の公式サイト](https://responder.readthedocs.io/en/latest/) を読んでください。