2. FlaskでOpenAPI定義の自動出力、Swagger UIページの作成

## Flask-RESTX の導入

[1. Flask 環境構築、簡単なバックエンドサーバー実装](https://qiita.com/YamaguchiRyuta/items/69ab10959767e27b8787)では
エンドポイントの実装の例を挙げてきましたが、ここでFlaskをもう少し簡潔に記述するために [Flask-RESTX](https://flask-restx.readthedocs.io/en/latest/index.html) を導入します。

まずは[Flask-RESTX](https://flask-restx.readthedocs.io/en/latest/index.html)のインストールです。

```bash
pip install flask-restx
```

app.pyを編集します。

```python:app.py
from flask import Flask, request
from flask_restx import Resource, Api

app = Flask(__name__)  # ここまでは同じ
api = Api(app)  # Flask に Flask-RESTX を導入


@api.route('/hello/<name>/<email>')
class Hello(Resource):
    def get(self, name, email):
        return {
            "name": name,
            "email": email
        }

    def post(self, name, email):
        body = request.json
        return {
            "name": name,
            "email": email,
            "body": body,
        }
```

これでGET, POST 両方に`/hello/{name}/{email}`に対応したエンドポイントを定義できました。

:::note warn
関数名はメソッド名と一致しなければいけません。
「get」ではない「my_get」のような名前に変えるとGETリクエストの定義がされません。
:::


[http://127.0.0.1:5000/hello/MyName001/aaa@bbb.ccc](http://127.0.0.1:5000/hello/MyName001/aaa@bbb.ccc)
をブラウザで開いてみましょう。json形式のBodyが返ってくるはずです。

```json
{
  "name": "MyName001",
  "email": "aaa@bbb.ccc"
}
```

GETに続いて`/hello/{name}/{email}`への POSTを試したいところですが
わざわざプログラムを書いて試すのはめんどくさいです。

Swaggerを使いましょう！

---

## OpenAPI + Swagger UI

本来であれば [OpenAPI](https://swagger.io/resources/open-api/) 定義(json or yaml)を記述し、それを[Swagger UI](https://swagger.io/tools/swagger-ui/)に読みこませることで静的Htmlファイルを生成することになりますが、

実は既に終わっています。

ブラウザで[http://127.0.0.1:5000/](http://127.0.0.1:5000/)を開いてみてください。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/611565/0bf8a022-c23a-8b4b-c43b-498a5ea624aa.png)

Flask-RESTXがPythonコードを基に自動でSwagger UI生成までやってくれます。
超便利です。
ですが、この段階ではPOSTリクエストにBodyを付けることはできません。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/611565/b3125252-c995-2108-007a-d89941cd8fda.png)

---

### POSTリクエストにBodyを指定できるように修正

コードは以下になります。

```python:app.py
from flask import Flask, request
from flask_restx import Resource, Api, fields  # <- 追加

app = Flask(__name__)
api = Api(app)

# 追加 -------------------------------
resource_fields = api.model("Json Bodyです", {
    "key1": fields.String,
    "key2": fields.Integer,
    "key3": fields.Boolean,
})
# -----------------------------------

@api.route('/hello/<name>/<email>')
class Hello(Resource):
    def get(self, name, email):
        return {
            "name": name,
            "email": email
        }

    @api.doc(body=resource_fields)  # <- 追加
    def post(self, name, email):
        body = request.json
        return {
            "name": name,
            "email": email,
            "body": body,
        }

```


ページを更新するとpayload欄が表示されています。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/611565/7e578ebc-fb89-1fcd-0e45-634e6a108ffb.png)

---

### OpenAPIを充実させる

このように`@api.doc()`などのデコレータを使って補足情報を追加していきます。

```python
from flask import Flask, request
from flask_restx import Resource, Api, fields

app = Flask(__name__)
api = Api(app, version='1.0', title='Sample API Documentation', description='A sample API')  # <- タイトルなどを変更

resource_fields = api.model("Json Bodyです", {
    "key1": fields.String,
    "key2": fields.Integer,
    "key3": fields.Boolean,
})


@api.route('/hello/<name>/<email>')
@api.doc(params={'name': '名前です', 'email': 'E-mailです'})  # <- 各パラメータの補足を追加
class Hello(Resource):
    def get(self, name, email):
        return {
            "name": name,
            "email": email
        }

    @api.doc(body=resource_fields)
    @api.doc(responses={400: '無効なBody'})  # <- HTTPコード, 補足を追加
    def post(self, name, email):
        body = request.json

        # 追加 -------------------
        if not body:
            api.abort(400)
        # -----------------------

        return {
            "name": name,
            "email": email,
            "body": body,
        }
```

ページを更新すると少し充実したドキュメントになっていると思います。

---

- [1. Flask 環境構築、簡単なバックエンドサーバー実装](https://qiita.com/YamaguchiRyuta/items/69ab10959767e27b8787)
- [2. FlaskでOpenAPI定義の自動出力、Swagger UIページの作成](https://qiita.com/YamaguchiRyuta/items/617c0299ea7277af4d9b) <-
- [3. FlaskでORM + MigrationでSQLを一切書かずにDBのCRUDや移行を行う](https://qiita.com/YamaguchiRyuta/items/dd88089b2fd41ea91745)
- [4. FlaskアプリをAWSにデプロイ](https://qiita.com/YamaguchiRyuta/items/ffc64586a40dd9a76742)