是否要為輸入和輸出使用單獨的 OpenAPI 模式¶
當使用 Pydantic v2 時,生成的 OpenAPI 比以前更精確且正確。😎
事實上,在某些情況下,它在 OpenAPI 中甚至會為同一個 Pydantic 模型提供兩個 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
# Code below omitted 👇
👀 完整檔案預覽
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
# Code below omitted 👇
👀 完整檔案預覽
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
# Code below omitted 👇
👀 完整檔案預覽
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
# Code below omitted 👇
👀 完整檔案預覽
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
欄位中新增任何內容,JSON 回應也包含預設值 (null
)。

這表示它將始終有一個值,只是有時該值可能是 None
(或 JSON 中的 null
)。
這表示,使用您的 API 的用戶端不必檢查該值是否存在,他們可以假設該欄位始終存在,只是在某些情況下它會具有 None
的預設值。
在 OpenAPI 中描述這種情況的方法是將該欄位標記為必填,因為它始終存在。
因此,模型的 JSON 模式可能會根據它用於輸入還是輸出而有所不同。
- 對於輸入,
description
將非必填。 - 對於輸出,它將是必填的(並且可能是
None
,或者用 JSON 術語來說是null
)。
文件中的輸出模型¶
您也可以在文件中檢查輸出模型,name
和 description
都用紅色星號標記為必填。

文件中的輸入和輸出模型¶
如果您檢查 OpenAPI 中所有可用的模式(JSON 模式),您將看到有兩個,一個是 Item-Input
,另一個是 Item-Output
。
對於 Item-Input
,description
非必填,它沒有紅色星號。
但是對於 Item-Output
,description
是必填的,它有一個紅色星號。

藉由 Pydantic v2 的這個功能,您的 API 文件將更加精確,而且如果您有自動生成的客戶端和 SDK,它們也會更加精確,提供更好的開發者體驗和一致性。🎉
不要區分 Schema¶
現在,在某些情況下,您可能希望輸入和輸出使用相同的 Schema。
主要的應用場景可能是您已經有一些自動生成的客戶端程式碼/SDK,並且您還不想更新所有自動生成的客戶端程式碼/SDK,您可能最終會想要更新,但或許不是現在。
在這種情況下,您可以使用參數 separate_input_output_schemas=False
在 FastAPI 中停用此功能。
資訊
FastAPI 0.102.0
版本開始支援 separate_input_output_schemas
。🤓
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"),
]
文件中輸入和輸出模型使用相同的 Schema¶
現在模型的輸入和輸出將只有一個 Schema,即 Item
,並且 description
將被設定為非必要

這與 Pydantic v1 的行為相同。🤓