入力と出力でOpenAPIのスキーマを分けるかどうか¶
🌐 AI と人間による翻訳
この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝
原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖
AI LLM をより適切に誘導するのを手伝う ことで、この翻訳を改善できます。
Pydantic v2 のリリース以降、生成される OpenAPI は以前より少し正確で、より正しいものになりました。😎
実際には、場合によっては同じ Pydantic モデルに対して、入力用と出力用で OpenAPI に 2 つの JSON Schema が含まれることがあります。これは デフォルト値 の有無に依存します。
その動作と、必要に応じての変更方法を見ていきます。
入出力のPydanticモデル¶
次のようにデフォルト値を持つ Pydantic モデルがあるとします。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
# Code below omitted 👇
👀 Full file preview
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
入力用モデル¶
このモデルを次のように入力として使うと:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
# Code below omitted 👇
👀 Full file preview
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
...description フィールドは 必須ではありません。デフォルト値が None だからです。
ドキュメントでの入力モデル¶
ドキュメントで確認すると、description フィールドには 赤いアスタリスク が付いておらず、必須としてはマークされていません:
出力用モデル¶
しかし同じモデルを次のように出力として使う場合:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
...description にデフォルト値があるため、そのフィールドに何も返さなくても、その デフォルト値 が入ります。
出力のレスポンスデータ¶
ドキュメントから試してレスポンスを確認すると、コードでは一方の description フィールドに何も追加していないにもかかわらず、JSON レスポンスにはデフォルト値(null)が含まれています:
つまりそのフィールドには 常に値があります。値が None(JSON では null)になることがあるだけです。
したがって、この API を使うクライアントは値の有無を確認する必要がなく、フィールドが 常に存在する と仮定できます。場合によってはデフォルト値の None になるだけです。
これを OpenAPI で表現するには、そのフィールドを 必須 としてマークします。常に存在するためです。
このため、モデルの JSON Schema は、入力か出力か によって異なる場合があります:
- 入力 では
descriptionは 必須ではない - 出力 では 必須(値は
None、JSON ではnullの可能性あり)
ドキュメントでの出力モデル¶
ドキュメントで出力モデルを見ると、name と description の 両方 が 赤いアスタリスク で 必須 としてマークされています:
ドキュメントでの入力・出力モデル¶
さらに、OpenAPI に含まれる利用可能なスキーマ(JSON Schema)を確認すると、Item-Input と Item-Output の 2 つがあることが分かります。
Item-Input では、description は 必須ではありません(赤いアスタリスクなし)。
一方、Item-Output では、description は 必須(赤いアスタリスクあり)です。
この Pydantic v2 の機能により、API ドキュメントはより 正確 になり、自動生成されたクライアントや SDK もより正確になります。これにより、より良い 開発者エクスペリエンス と一貫性が得られます。🎉
スキーマを分けない¶
一方で、入力と出力で同じスキーマ にしたい場合もあります。
主なユースケースは、すでに自動生成されたクライアントコードや SDK があり、まだそれらをすべて更新したくない場合です。いずれは更新したいとしても、今ではないかもしれません。
その場合は、FastAPI のパラメータ separate_input_output_schemas=False でこの機能を無効化できます。
情報
separate_input_output_schemas のサポートは FastAPI 0.102.0 で追加されました。🤓
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
app = FastAPI(separate_input_output_schemas=False)
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/")
def read_items() -> list[Item]:
return [
Item(
name="Portal Gun",
description="Device to travel through the multi-rick-verse",
),
Item(name="Plumbus"),
]
ドキュメントで入力・出力に同一スキーマを使用¶
これでモデルの入力と出力は単一のスキーマ、Item のみになり、description は 必須ではありません: