入力と出力にOpenAPIスキーマを分けるかどうか¶
Pydantic v2を使用する場合、生成されるOpenAPIは以前よりも少し正確で正しいものです。😎
実際、場合によっては、同じPydanticモデルに対して、入力用と出力用で、デフォルト値があるかどうかによって、OpenAPI内に2つのJSONスキーマを持つことがあります。
その仕組みと、必要に応じて変更する方法を見てみましょう。
入力と出力のためのPydanticモデル¶
以下のように、デフォルト値を持つPydanticモデルがあるとしましょう。
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
# Code below omitted 👇
👀 ファイル全体のプレビュー
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 typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = 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 typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[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 👇
👀 ファイル全体のプレビュー
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 typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = 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 typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[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"),
]
🤓 その他のバージョンとバリアント
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = 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 typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[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
フィールドの1つに何も追加していませんが、JSON応答にはデフォルト値(null
)が含まれています。

これは、常に値を持つことを意味し、その値がNone
(またはJSONではnull
)になる場合があるということです。
つまり、APIを使用するクライアントは、値が存在するかどうかをチェックする必要はなく、フィールドは常に存在すると仮定できますが、場合によってはNone
というデフォルト値を持つということです。
これをOpenAPIで記述する方法は、そのフィールドを必須としてマークすることです。なぜなら、それは常に存在するからです。
そのため、モデルのJSONスキーマは、入力用か出力用かによって異なる場合があります。
- 入力用の場合、
description
は必須ではありません。 - 出力用の場合、それは必須です(そして、おそらく
None
、またはJSON用語ではnull
)。
ドキュメント内の出力モデル¶
ドキュメント内の出力モデルも確認できます。name
とdescription
の両方が赤いアスタリスクで必須としてマークされています。

ドキュメント内の入力と出力のモデル¶
OpenAPIで利用可能なすべてのスキーマ (JSONスキーマ) を確認すると、Item-Input
とItem-Output
の2つがあることがわかります。
Item-Input
の場合、description
は必須ではありません。赤いアスタリスクはありません。
しかし、Item-Output
の場合、description
は必須です。赤いアスタリスクがあります。

Pydantic v2のこの機能により、APIドキュメントはより正確になり、自動生成されたクライアントやSDKがある場合も、より正確になり、より良い開発者体験と一貫性が得られます。🎉
スキーマを分離しない¶
さて、入力と出力で同じスキーマを使用したい場合もあります。
おそらく主なユースケースは、すでに自動生成されたクライアントコード/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"),
]
🤓 その他のバージョンとバリアント
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = 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"),
]
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[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
は必須ではありません。

これはPydantic v1と同じ動作です。🤓