リクエストボディ¶
クライアント (ブラウザなど) からAPIにデータを送信する必要があるとき、データを リクエストボディ (request body) として送ります。
リクエスト ボディはクライアントによってAPIへ送られます。レスポンス ボディはAPIがクライアントに送るデータです。
APIはほとんどの場合 レスポンス ボディを送らなければなりません。しかし、クライアントは必ずしも リクエスト ボディを送らなければいけないわけではありません。
リクエスト ボディを宣言するために Pydantic モデルを使用します。そして、その全てのパワーとメリットを利用します。
情報
データを送るには、POST (もっともよく使われる)、PUT、DELETE または PATCH を使うべきです。
GET リクエストでボディを送信することは、仕様では未定義の動作ですが、FastAPI でサポートされており、非常に複雑な(極端な)ユースケースにのみ対応しています。
非推奨なので、Swagger UIを使った対話型のドキュメントにはGETのボディ情報は表示されません。さらに、中継するプロキシが対応していない可能性があります。
Pydanticの BaseModel をインポート¶
ます初めに、 pydantic から BaseModel をインポートする必要があります:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
データモデルの作成¶
そして、BaseModel を継承したクラスとしてデータモデルを宣言します。
すべての属性にpython標準の型を使用します:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
クエリパラメータの宣言と同様に、モデル属性がデフォルト値をもつとき、必須な属性ではなくなります。それ以外は必須になります。オプショナルな属性にしたい場合は None を使用してください。
例えば、上記のモデルは以下の様なJSON「オブジェクト」(もしくはPythonの dict ) を宣言しています:
{
"name": "Foo",
"description": "An optional description",
"price": 45.2,
"tax": 3.5
}
...description と tax はオプショナル (デフォルト値は None) なので、以下のJSON「オブジェクト」も有効です:
{
"name": "Foo",
"price": 45.2
}
パラメータとして宣言¶
パスオペレーション に加えるために、パスパラメータやクエリパラメータと同じ様に宣言します:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
...そして、作成したモデル Item で型を宣言します。
結果¶
そのPythonの型宣言だけで FastAPI は以下のことを行います:
- リクエストボディをJSONとして読み取ります。
- 適当な型に変換します(必要な場合)。
- データを検証します。
- データが無効な場合は、明確なエラーが返され、どこが不正なデータであったかを示します。
- 受け取ったデータをパラメータ
itemに変換します。- 関数内で
Item型であると宣言したので、すべての属性とその型に対するエディタサポート(補完など)をすべて使用できます。
- 関数内で
- モデルのJSONスキーマ定義を生成し、好きな場所で使用することができます。
- これらのスキーマは、生成されたOpenAPIスキーマの一部となり、自動ドキュメントのUIに使用されます。
自動ドキュメント生成¶
モデルのJSONスキーマはOpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:

そして、それらが使われる パスオペレーション のそれぞれのAPIドキュメントにも表示されます:

エディターサポート¶
エディターによる型ヒントと補完が関数内で利用できます (Pydanticモデルではなく dict を受け取ると、同じサポートは受けられません):

型によるエラーチェックも可能です:

これは偶然ではなく、このデザインに基づいてフレームワークが作られています。
全てのエディターで機能することを確認するために、実装前の設計時に徹底的にテストしました。
これをサポートするためにPydantic自体にもいくつかの変更がありました。
上記のスクリーンショットはVisual Studio Codeを撮ったものです。
しかし、PyCharmやほとんどのPythonエディタでも同様なエディターサポートを受けられます:

豆知識
PyCharmエディタを使用している場合は、Pydantic PyCharm Pluginが使用可能です。
以下のエディターサポートが強化されます:
- 自動補完
- 型チェック
- リファクタリング
- 検索
- インスペクション
モデルの使用¶
関数内部で、モデルの全ての属性に直接アクセスできます:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
リクエストボディ + パスパラメータ¶
パスパラメータとリクエストボディを同時に宣言できます。
FastAPI はパスパラメータである関数パラメータはパスから受け取り、Pydanticモデルによって宣言された関数パラメータはリクエストボディから受け取るということを認識します。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, **item.dict()}
リクエストボディ + パスパラメータ + クエリパラメータ¶
また、ボディとパスとクエリのパラメータも同時に宣言できます。
FastAPI はそれぞれを認識し、適切な場所からデータを取得します。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: Union[str, None] = None):
result = {"item_id": item_id, **item.dict()}
if q:
result.update({"q": q})
return result
関数パラメータは以下の様に認識されます:
- パラメータがパスで宣言されている場合は、優先的にパスパラメータとして扱われます。
- パラメータが単数型 (
int、float、str、boolなど)の場合はクエリパラメータとして解釈されます。 - パラメータが Pydantic モデル型で宣言された場合、リクエストボディとして解釈されます。
備考
FastAPIは、= Noneがあるおかげで、qがオプショナルだとわかります。
Optional[str] のOptional はFastAPIでは使用されていません(FastAPIはstrの部分のみ使用します)。しかし、Optional[str] はエディタがコードのエラーを見つけるのを助けてくれます。
Pydanticを使わない方法¶
もしPydanticモデルを使用したくない場合は、Bodyパラメータが利用できます。Body - Multiple Parameters: Singular values in bodyを確認してください。