9.2 KiB
レスポンスモデル
path operations のいずれにおいても、response_modelパラメータを使用して、レスポンスのモデルを宣言することができます:
@app.get()@app.post()@app.put()@app.delete()- など。
{!../../docs_src/response_model/tutorial001.py!}
/// note | 備考
response_modelは「デコレータ」メソッド(get、postなど)のパラメータであることに注意してください。すべてのパラメータやボディのように、path operation関数 のパラメータではありません。
///
Pydanticモデルの属性に対して宣言するのと同じ型を受け取るので、Pydanticモデルになることもできますが、例えば、List[Item]のようなPydanticモデルのlistになることもできます。
FastAPIはresponse_modelを使って以下のことをします:
- 出力データを型宣言に変換します。
- データを検証します。
- OpenAPIの path operation で、レスポンス用のJSON Schemaを追加します。
- 自動ドキュメントシステムで使用されます。
しかし、最も重要なのは:
- 出力データをモデルのデータに限定します。これがどのように重要なのか以下で見ていきましょう。
/// note | 技術詳細
レスポンスモデルは、関数の戻り値のアノテーションではなく、このパラメータで宣言されています。なぜなら、パス関数は実際にはそのレスポンスモデルを返すのではなく、dictやデータベースオブジェクト、あるいは他のモデルを返し、response_modelを使用してフィールドの制限やシリアライズを行うからです。
///
同じ入力データの返却
ここではUserInモデルを宣言しています。それには平文のパスワードが含まれています:
{!../../docs_src/response_model/tutorial002.py!}
そして、このモデルを使用して入力を宣言し、同じモデルを使って出力を宣言しています:
{!../../docs_src/response_model/tutorial002.py!}
これで、ブラウザがパスワードを使ってユーザーを作成する際に、APIがレスポンスで同じパスワードを返すようになりました。
この場合、ユーザー自身がパスワードを送信しているので問題ないかもしれません。
しかし、同じモデルを別のpath operationに使用すると、すべてのクライアントにユーザーのパスワードを送信してしまうことになります。
/// danger | 危険
ユーザーの平文のパスワードを保存したり、レスポンスで送信したりすることは絶対にしないでください。
///
出力モデルの追加
代わりに、平文のパスワードを持つ入力モデルと、パスワードを持たない出力モデルを作成することができます:
{!../../docs_src/response_model/tutorial003.py!}
ここでは、path operation関数がパスワードを含む同じ入力ユーザーを返しているにもかかわらず:
{!../../docs_src/response_model/tutorial003.py!}
...response_modelをUserOutと宣言したことで、パスワードが含まれていません:
{!../../docs_src/response_model/tutorial003.py!}
そのため、FastAPI は出力モデルで宣言されていない全てのデータをフィルタリングしてくれます(Pydanticを使用)。
ドキュメントを見る
自動ドキュメントを見ると、入力モデルと出力モデルがそれぞれ独自のJSON Schemaを持っていることが確認できます。
そして、両方のモデルは、対話型のAPIドキュメントに使用されます:
レスポンスモデルのエンコーディングパラメータ
レスポンスモデルにはデフォルト値を設定することができます:
{!../../docs_src/response_model/tutorial004.py!}
description: str = NoneはNoneがデフォルト値です。tax: float = 10.5は10.5がデフォルト値です。tags: List[str] = []は空のリスト([])がデフォルト値です。
しかし、実際に保存されていない場合には結果からそれらを省略した方が良いかもしれません。
例えば、NoSQLデータベースに多くのオプション属性を持つモデルがあるが、デフォルト値でいっぱいの非常に長いJSONレスポンスを送信したくない場合です。
response_model_exclude_unsetパラメータの使用
path operation デコレータにresponse_model_exclude_unset=Trueパラメータを設定することができます:
{!../../docs_src/response_model/tutorial004.py!}
そして、これらのデフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。
そのため、path operationにIDfooが設定されたitemのリクエストを送ると、レスポンスは以下のようになります(デフォルト値を含まない):
{
"name": "Foo",
"price": 50.2
}
/// info | 情報
FastAPIはこれをするために、Pydanticモデルの.dict()をそのexclude_unsetパラメータで使用しています。
///
/// info | 情報
以下も使用することができます:
response_model_exclude_defaults=Trueresponse_model_exclude_none=True
exclude_defaultsとexclude_noneについては、Pydanticのドキュメントで説明されている通りです。
///
デフォルト値を持つフィールドの値を持つデータ
しかし、IDbarのitemのように、デフォルト値が設定されているモデルのフィールドに値が設定されている場合:
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2
}
それらはレスポンスに含まれます。
デフォルト値と同じ値を持つデータ
IDbazのitemのようにデフォルト値と同じ値を持つデータの場合:
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
FastAPIは十分に賢いので(実際には、Pydanticが十分に賢い)descriptionやtax、tagsはデフォルト値と同じ値を持っているにもかかわらず、明示的に設定されていることを理解しています。(デフォルトから取得するのではなく)
そのため、それらはJSONレスポンスに含まれることになります。
/// tip | 豆知識
デフォルト値はNoneだけでなく、なんでも良いことに注意してください。
例えば、リスト([])や10.5のfloatなどです。
///
response_model_includeとresponse_model_exclude
path operationデコレータとしてresponse_model_includeとresponse_model_excludeも使用することができます。
属性名を持つstrのsetを受け取り、含める(残りを省略する)か、除外(残りを含む)します。
これは、Pydanticモデルが1つしかなく、出力からいくつかのデータを削除したい場合のクイックショートカットとして使用することができます。
/// tip | 豆知識
それでも、これらのパラメータではなく、複数のクラスを使用して、上記のようなアイデアを使うことをおすすめします。
これはresponse_model_includeやresponse_mode_excludeを使用していくつかの属性を省略しても、アプリケーションのOpenAPI(とドキュメント)で生成されたJSON Schemaが完全なモデルになるからです。
同様に動作するresponse_model_by_aliasにも当てはまります。
///
{!../../docs_src/response_model/tutorial005.py!}
/// tip | 豆知識
{"name", "description"}の構文はこれら2つの値をもつsetを作成します。
これはset(["name", "description"])と同等です。
///
setの代わりにlistを使用する
もしsetを使用することを忘れて、代わりにlistやtupleを使用しても、FastAPIはそれをsetに変換して正しく動作します:
{!../../docs_src/response_model/tutorial006.py!}
まとめ
path operationデコレータのresponse_modelパラメータを使用して、レスポンスモデルを定義し、特にプライベートデータがフィルタリングされていることを保証します。
明示的に設定された値のみを返すには、response_model_exclude_unsetを使用します。