コンテンツへスキップ

リクエストボディ

クライアント (例えばブラウザ) からAPIにデータを送信する必要がある場合、リクエストボディとして送信します。

リクエストボディは、クライアントがAPIに送信するデータです。レスポンスボディは、APIがクライアントに送信するデータです。

APIはほとんどの場合、レスポンスボディを送信する必要があります。しかし、クライアントは常にリクエストボディを送信する必要はありません。パスをリクエストするだけで、クエリパラメーターをいくつか含めることもありますが、ボディを送信しないこともあります。

リクエストボディを宣言するには、Pydanticモデルをそのすべての機能と利点とともに使用します。

情報

データを送信するには、POST (最も一般的)、PUTDELETE、またはPATCHのいずれかを使用する必要があります。

GETリクエストでボディを送信することは、仕様で未定義の動作ですが、FastAPIでは非常に複雑な/極端なユースケースの場合にのみサポートされています。

推奨されないため、Swagger UIでのインタラクティブなドキュメントでは、GETを使用する場合にボディのドキュメントは表示されず、途中のプロキシがサポートしない可能性があります。

PydanticのBaseModelをインポートする

まず、pydanticからBaseModelをインポートする必要があります。

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 その他のバージョンとバリアント
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 fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 その他のバージョンとバリアント
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 "object" (またはPython dict) を宣言しています。

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

...descriptiontaxはオプション (デフォルト値はNone) なので、このJSON "object" も有効です。

{
    "name": "Foo",
    "price": 45.2
}

パラメーターとして宣言する

それをパスオペレーションに追加するには、パスパラメーターやクエリパラメーターを宣言したのと同じ方法で宣言します。

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 その他のバージョンとバリアント
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 Schema定義を生成します。プロジェクトにとって意味がある場合は、他のどこでも使用できます。
  • これらのスキーマは、生成されたOpenAPIスキーマの一部となり、自動ドキュメントUIで使用されます。

自動ドキュメント

モデルのJSONスキーマは、生成されたOpenAPIスキーマの一部となり、インタラクティブなAPIドキュメントに表示されます。

また、それらを必要とする各パスオペレーション内のAPIドキュメントでも使用されます。

エディターのサポート

エディタの関数内で、型ヒントと補完がいたるところで得られます(Pydanticモデルの代わりにdictを受け取った場合はこれは起こりません)。

不正な型操作に対するエラーチェックも行われます。

これは偶然ではなく、フレームワーク全体がその設計に基づいて構築されています。

また、実装前に設計段階で徹底的にテストされ、すべてのエディタで動作することが確認されています。

これをサポートするために、Pydantic自体にもいくつかの変更が加えられました。

以前のスクリーンショットはVisual Studio Codeで撮影されたものです。

しかし、PyCharmやほとんどの他のPythonエディターでも同じエディターサポートが得られます。

ヒント

エディタとしてPyCharmを使用している場合は、Pydantic PyCharm Pluginを使用できます。

Pydanticモデルのエディタサポートが向上し、以下が提供されます。

  • オートコンプリート
  • 型チェック
  • リファクタリング
  • 検索
  • 検査

モデルを使用する

関数内では、モデルオブジェクトのすべての属性に直接アクセスできます。

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax is not None:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict
🤓 その他のバージョンとバリアント
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 is not None:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict

リクエストボディ + パスパラメーター

パスパラメーターとリクエストボディを同時に宣言できます。

FastAPIは、パスパラメーターと一致する関数パラメーターがパスから取得されること、およびPydanticモデルとして宣言された関数パラメーターがリクエストボディから取得されることを認識します。

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: 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()}
🤓 その他のバージョンとバリアント
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 fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result
🤓 その他のバージョンとバリアント
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の値が必須ではないことを認識します。

str | None (Python 3.10+) またはUnion[str, None] (Python 3.8+) のUnionは、FastAPIが値が必須ではないことを判断するために使用されるわけではありません。デフォルト値が= Noneであるため、必須ではないことを認識します。

しかし、型アノテーションを追加することで、エディターがより良いサポートを提供し、エラーを検出できるようになります。

Pydanticなし

Pydanticモデルを使いたくない場合は、Bodyパラメータを使うこともできます。詳しくはボディ - 複数のパラメータ: ボディ内の単一値のドキュメントを参照してください。