单独为输入和输出定义 OpenAPI Schema 或不定义¶
自 Pydantic v2 发布以来,生成的 OpenAPI 比以前更加精确和正确。😎
实际上,在某些情况下,同一个 Pydantic 模型在 OpenAPI 中会生成两个 JSON Schema,分别用于输入和输出,具体取决于它们是否具有默认值。
让我们看看这是如何工作的,以及如果你需要这样做,如何更改它。
用于输入和输出的 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 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"),
]
...那么 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"),
]
...那么由于 description 有一个默认值,如果你没有为该字段返回任何内容,它仍然会具有该默认值。
用于输出响应数据的模型¶
如果你与文档交互并检查响应,即使代码在 description 字段的一个中没有添加任何内容,JSON 响应也包含默认值 (null)
这意味着它将始终有一个值,只是有时该值可能是 None (在 JSON 中为 null)。
这意味着使用你 API 的客户端不必检查值是否存在,它们可以假定该字段始终存在,只是在某些情况下它将具有 None 的默认值。
在 OpenAPI 中描述这一点的方式是,将该字段标记为必需,因为它将始终存在。
因此,模型的 JSON Schema 可以根据它是用于输入还是输出而有所不同
- 对于输入,
description将不是必需的 - 对于输出,它将是必需的 (并且可能是
None,或者用 JSON 的术语来说,是null)
文档中的输出模型¶
你也可以在文档中检查输出模型,name 和 description 都被标记为必需,并带有红色星号
文档中的输入和输出模型¶
如果你查看 OpenAPI 中所有可用的 Schema (JSON Schema),你会发现有两个,一个 Item-Input 和一个 Item-Output。
对于 Item-Input,description不是必需的,它没有红色星号。
但对于 Item-Output,description 是必需的,它有一个红色星号。
通过 Pydantic v2 的这项功能,你的 API 文档将更加精确,如果你有自动生成的客户端和 SDK,它们也将更加精确,具有更好的开发者体验和一致性。🎉
不单独定义 Schema¶
现在,在某些情况下,你可能希望输入和输出使用相同的 Schema。
这可能最主要的用例是你已经拥有一些自动生成的客户端代码/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"),
]
文档中输入和输出模型相同的 Schema¶
现在,该模型将有一个用于输入和输出的单一 Schema,只有 Item,并且 description 将不是必需的