Python responder v2 入門

responder v2.0.0 が 2019-10-19(JST) にリリースされました！
だいぶ時間が経ってしまいましたが，v1 からの変更点を調べたので紹介します。

ちなみに v1.3.2 からの後方互換性が確保されているようですので，v2.0.5 にバージョンアップしても問題ありません。

## 対象読者
* responder v1 を使っている方，使い方がわかっている方
* responder v2 で何が変わったのかを知りたい方

今回，v1 系からの変更点のみをとりあげます。
**その他の部分についてはぜひ [Python responder 入門のために… 下調べ - Qiita](https://qiita.com/y_k/items/6e4da3bef5c8d8bd2730) を参照してください！**

## 新しい Router と Schema (ついでに Template)
Schema，Template の記法が変わりました！
また，Router 周りのリファクタリングが行われました（正直ユーザには関係ない）。

今までインポート1つで済み，1つのインスタンスでなんでもできる点が良くも悪くも特長でした。

```python
import responder

api = responder.API()
```

しかし，Scheme や Template の定義にも `api` が必要であり，ファイル分離が少し手間でした。
新しい v2 ではこれらは分離され，多少はファイルの分離が楽になりました。

### Router
リファクタリングが行われました。
今のところユーザ側に変更はないように思います。

### Schema
新しく `responder.ext.schema` のインポート (`from responder.ext.schema import Schema as OpenAPISchema`など) が必要になりました。
ただし，こちらは `responder.ext.schema.Schema` インタンスの生成時に `api` に依存し，このインスタンスが各スキーマ定義時に必要なため，ファイル分離にはコツがいるのは今まで通りです…

```python:新しい書き方
import responder
from responder.ext.schema import Schema as OpenAPISchema
from marshmallow import Schema, fields

contact = {
    "name": "API Support",
    "url": "http://www.example.com/support",
    "email": "support@example.com",
}
license = {
    "name": "Apache 2.0",
    "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
}

api = responder.API()

schema = OpenAPISchema(
    app=api,
    title="Web Service",
    version="1.0",
    openapi="3.0.2",
    docs_route='/docs',  # ドキュメント提供する場合
    description="A simple pet store",
    terms_of_service="http://example.com/terms/",
    contact=contact,
    license=license,
)

@schema.schema("Pet")
class PetSchema(Schema):
    name = fields.Str()

@api.route("/")
def route(req, resp):
    """A cute furry animal endpoint.
    ---
    get:
        description: Get a random pet
        responses:
            200:
                description: A pet to be returned
                content:  
                    application/json: 
                        schema: 
                            $ref: '#/components/schemas/Pet'                         
    """
    resp.media = PetSchema().dump({"name": "little orange"})
```

なお，こちらも今までの書き方でも動くようですが推奨されていないので，既存の書き方は省略します。

### Template
テンプレート機能は既存のものに加え，以下のように実装可能です:

```python:新しく分離されたテンプレート機能
from responder.templates import Templates

templates = Templates()

@api.route("/hello/{name}/html")
def hello(req, resp, name):
    resp.html = templates.render("hello.html", name=name)
```
      
また，非同期レンダリング `render_async` にも対応しました:

```python:テンプレートの非同期レンダリング
from responder.templates import Templates

templates = Templates(enable_async=True)

resp.html = await templates.render_async("hello.html", name=name)
```

既存パターンも利用可能です:

```python:既存のテンプレート機能
import responder

api = responder.API()

@api.route("/hello/{name}/html")
def hello_html(req, resp, *, who):
    resp.html = api.template('hello.html', name=name)
```

## Python 3.8 への対応
v2.0.5 からは Python 3.8 にサポートしました。

## あとがき
中規模のウェブアプリケーションは実装しやすくなったのかも知れませんね。

## 参考
* [responder/CHANGELOG.md at master · taoufik07/responder](https://github.com/taoufik07/responder/blob/master/CHANGELOG.md)
* [Comparing v1.3.2...v2.0.5 · taoufik07/responder](https://github.com/taoufik07/responder/compare/v1.3.2...v2.0.5)