是否为输入和输出分别生成 OpenAPI JSON 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 👇
👀 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 中可用的所有 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"),
]
文档中输入/输出使用同一 Schema 的模型¶
现在该模型的输入和输出将只使用一个 schema,即 Item,并且其中的 description 不是必填: