Open1
FastAPIのBody(embed=True)でハマった話:/docsが利口すぎて気づきにくい罠

FastAPIの Body(embed=True)
は「受け取るリクエストJSONの形」を縛るだけ
/docsでは最初から「⚪︎⚪︎キーでラップした正しい形」が提示されるので、間違った例を試さないとエラーを確認できずハマった体験談
embed=Trueは「⚪︎⚪︎キーでラップしたJSONを要求する」という設計になる
/docsはその「正しい形」を最初から自動生成してくれる
逆に言うと「⚪︎⚪︎キーを外した間違ったリクエストを試さないと気づけない」
/docs(Swagger UI)って何?
FastAPIではサーバーを起動すると、標準で自動生成ドキュメントが使えるようになる
例
uvicorn main:app --reload
を実行してサーバーを立ち上げたら、
http://127.0.0.1:8000/docs
にブラウザでアクセスするだけで、Swagger UI形式のドキュメントが表示される
特徴
- 自動でOpenAPIスキーマを解析して、APIエンドポイントやリクエスト例を表示
- その場でリクエストを試せる
- 返却されるレスポンスを確認できる
(↓docs画面)
どんな詰まり方をしたか
FastAPIで以下のようにエンドポイントを定義。
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = Field(
default=None, title="The description of the item", max_length=300
)
price: float = Field(gt=0, description="The price must be greater than zero")
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(embed=True)):
results = {"item_id": item_id, "item": item}
return results
/docs(Swagger UI)では、リクエストボディ例が自動でこう出る。
{
"item": {
"name": "string",
"description": "string",
"price": 1,
"tax": 0
}
}
これをそのまま送ればもちろん成功するので、何も気づかず通ってしまう。
でも本質は、「itemというキーでラップした形を必ず送らないといけない」というAPI設計になる。
例えば itemキーを外して↓のように送ると
{
"name": "string",
"description": "string",
"price": 1,
"tax": 0
}
エラーになる。
{
"detail": [
{
"loc": ["body", "item"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
embed=True / Falseの比較
embed指定 | 期待するリクエストボディ |
---|---|
なし | { "name": "...", "price": ... } |
あり | { "item": { "name": "...", "price": ... } } |
embed=Trueを使うとどうなるか
- クライアントに「⚪︎⚪︎キーでラップしたJSONを送ってね」と強制する
- その形じゃないとバリデーションエラー
なぜ気づきにくかったか
- /docsはFastAPIの型定義を解析して「期待する正しいJSON例」を自動生成する
- embed=Trueを指定すると最初からitemキー付きの例しか出ない
- だから「itemキーを外したらどうなるか」を試さないとエラーを体験できない
解決策
- /docsでも意図的にフィールドを消してエラーを確認する
- Postmanやcurlなどを使って自由にリクエストボディを編集し、間違ったケースを試す
- embed=Trueを使うと「APIの受け取る形がこうなる」という設計をきちんと意識する
学び
- FastAPIのembed=Trueは「受け取るJSONを1階層包む」ための指定
- /docsは正しい形を出してくれるけど、逆に「間違った形を送るとどうなるか」を試すには1手間必要
- Postmanなどを併用して失敗ケースを体験するのが大事