声明请求示例数据¶
您可以声明应用程序可以接收的数据示例。
以下是一些方法。
Pydantic 模型中的额外 JSON Schema 数据¶
您可以为 Pydantic 模型声明 examples
,这些示例将被添加到生成的 JSON Schema 中。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
class Config:
schema_extra = {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class Config:
schema_extra = {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
这些额外信息将按原样添加到该模型的输出 JSON Schema 中,并将用于 API 文档。
在 Pydantic 版本 2 中,您将使用属性 model_config
,该属性接受一个 dict
,如 Pydantic 文档:配置 中所述。
您可以使用 "json_schema_extra"
设置一个 dict
,其中包含您希望在生成的 JSON Schema 中显示的任何额外数据,包括 examples
。
在 Pydantic 版本 1 中,您将使用内部类 Config
和 schema_extra
,如 Pydantic 文档:模式自定义 中所述。
您可以使用 schema_extra
设置一个 dict
,其中包含您希望在生成的 JSON Schema 中显示的任何额外数据,包括 examples
。
提示
您可以使用相同的技术来扩展 JSON Schema 并添加您自己的自定义额外信息。
例如,您可以使用它来添加前端用户界面的元数据等。
信息
OpenAPI 3.1.0(从 FastAPI 0.99.0 开始使用)添加了对 examples
的支持,它是 JSON Schema 标准的一部分。
在此之前,它只支持关键字 example
,它只有一个示例。OpenAPI 3.1.0 仍然支持它,但已弃用,并且不是 JSON Schema 标准的一部分。因此,建议您将 example
迁移到 examples
。🤓
您可以在本页末尾阅读更多内容。
Field
附加参数¶
使用 Pydantic 模型中的 Field()
时,您也可以声明额外的 examples
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str = Field(examples=["Foo"])
description: str | None = Field(default=None, examples=["A very nice Item"])
price: float = Field(examples=[35.4])
tax: float | None = Field(default=None, examples=[3.2])
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str = Field(examples=["Foo"])
description: Union[str, None] = Field(default=None, examples=["A very nice Item"])
price: float = Field(examples=[35.4])
tax: Union[float, None] = Field(default=None, examples=[3.2])
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
JSON Schema 中的 examples
- OpenAPI¶
使用以下任何一个
Path()
Query()
Header()
Cookie()
Body()
Form()
File()
您也可以声明一组 examples
,其中包含将在 OpenAPI 中的 JSON Schema 中添加的额外信息。
带 examples
的 Body
¶
在这里,我们传递包含 Body()
中预期数据的一个示例的 examples
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Annotated, Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Item = Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Item = Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
):
results = {"item_id": item_id, "item": item}
return results
文档 UI 中的示例¶
使用上面任何一种方法,在/docs
中看起来会是这样的
Body
带有多个examples
¶
当然,你也可以传递多个examples
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Annotated, Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item = Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item = Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
):
results = {"item_id": item_id, "item": item}
return results
当你这样做时,这些示例将成为该主体数据内部的 JSON Schema 的一部分。
然而,截至撰写本文时,Swagger UI(负责显示文档 UI 的工具)不支持显示 JSON Schema 中数据的多个示例。 但请阅读下面内容以了解解决方法。
OpenAPI 特定的examples
¶
在 JSON Schema 支持examples
之前,OpenAPI 就已经支持了另一个名为examples
的不同字段。
这个 OpenAPI 特定的 examples
位于 OpenAPI 规范中的另一个部分。它位于 每个路径操作的详细信息中,而不是每个 JSON Schema 内部。
Swagger UI 一直支持这个特定的examples
字段。 因此,你可以使用它来 在文档 UI 中显示不同的 示例。
这个 OpenAPI 特定的字段examples
的形状是一个dict
,它包含 多个示例(而不是一个list
),每个示例都包含将添加到 OpenAPI 的额外信息。
它不位于 OpenAPI 中包含的每个 JSON Schema 内部,而是位于外部,直接位于路径操作中。
使用openapi_examples
参数¶
你可以使用参数openapi_examples
在 FastAPI 中声明 OpenAPI 特定的examples
,用于
Path()
Query()
Header()
Cookie()
Body()
Form()
File()
dict
的键标识每个示例,每个值是另一个dict
。
examples
中的每个特定示例dict
都可以包含
summary
:示例的简短描述。description
:一个可以包含 Markdown 文本的较长描述。value
:这是显示的实际示例,例如一个dict
。externalValue
:value
的替代方案,一个指向示例的 URL。 尽管这可能不像value
那样得到许多工具的支持。
你可以像这样使用它
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
openapi_examples={
"normal": {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
},
"converted": {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"name": "Bar",
"price": "35.4",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Annotated, Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
openapi_examples={
"normal": {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
},
"converted": {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"name": "Bar",
"price": "35.4",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
],
):
results = {"item_id": item_id, "item": item}
return results
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
openapi_examples={
"normal": {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
},
"converted": {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"name": "Bar",
"price": "35.4",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
],
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item = Body(
openapi_examples={
"normal": {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
},
"converted": {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"name": "Bar",
"price": "35.4",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
):
results = {"item_id": item_id, "item": item}
return results
提示
如果可能,最好使用 Annotated
版本。
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item = Body(
openapi_examples={
"normal": {
"summary": "A normal example",
"description": "A **normal** item works correctly.",
"value": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
},
"converted": {
"summary": "An example with converted data",
"description": "FastAPI can convert price `strings` to actual `numbers` automatically",
"value": {
"name": "Bar",
"price": "35.4",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
):
results = {"item_id": item_id, "item": item}
return results
文档 UI 中的 OpenAPI 示例¶
在 Body()
中添加openapi_examples
后,/docs
将会显示
技术细节¶
提示
如果你已经在使用 FastAPI 版本 0.99.0 或更高版本,你可能可以 跳过这些细节。
它们在旧版本中更重要,在 OpenAPI 3.1.0 可用之前。
你可以将其视为关于 OpenAPI 和 JSON Schema 的简要 历史课程。🤓
警告
这些是关于 JSON Schema 和 OpenAPI 标准的非常技术性的细节。
如果上面的想法对你已经起作用,那可能就足够了,你可能不需要这些细节,可以随意跳过它们。
在 OpenAPI 3.1.0 之前,OpenAPI 使用了旧版且修改过的 JSON Schema。
JSON Schema 没有examples
,因此 OpenAPI 为其自己的修改版本添加了自己的example
字段。
OpenAPI 还将example
和examples
字段添加到规范的其他部分,
Parameter Object
(在规范中),被 FastAPI 的Path()
Query()
Header()
Cookie()
Request Body Object
,在content
字段中,在Media Type Object
上(在规范中),被 FastAPI 的Body()
File()
Form()
信息
这个旧的 OpenAPI 特定的examples
参数现在是openapi_examples
,自 FastAPI 0.103.0
开始。
JSON Schema 的examples
字段¶
但随后 JSON Schema 为规范的新版本添加了 examples
字段。
然后,新的 OpenAPI 3.1.0 基于最新版本(JSON Schema 2020-12)构建,该版本包含这个新的字段examples
。
现在,这个新的examples
字段优先于旧的单个(且自定义的)example
字段,该字段现在已弃用。
JSON Schema 中的这个新的examples
字段 只是一个list
示例,而不是像 OpenAPI 中其他地方(如上所述)那样带额外元数据的 dict。
信息
即使 OpenAPI 3.1.0 发布了这个与 JSON Schema 的新简化集成,在一段时间内,Swagger UI(提供自动文档的工具)不支持 OpenAPI 3.1.0(自版本 5.0.0 开始支持 🎉)。
因此,FastAPI 0.99.0 之前的版本仍然使用低于 3.1.0 的 OpenAPI 版本。
Pydantic 和 FastAPI examples
¶
当你使用schema_extra
或Field(examples=["something"])
在 Pydantic 模型中添加examples
时,该示例将添加到该 Pydantic 模型的 JSON Schema 中。
然后,Pydantic 模型的 JSON Schema 将包含在 API 的 OpenAPI 中,然后它将在文档 UI 中使用。
在 FastAPI 0.99.0 之前的版本中(0.99.0 及更高版本使用更新的 OpenAPI 3.1.0),当你使用example
或examples
与其他任何实用程序(Query()
、Body()
等)一起使用时,这些示例不会添加到描述该数据的 JSON Schema 中(甚至不会添加到 OpenAPI 自己版本的 JSON Schema 中),而是直接添加到 OpenAPI 的路径操作声明中(在使用 JSON Schema 的 OpenAPI 部分之外)。
但现在 FastAPI 0.99.0 及更高版本使用 OpenAPI 3.1.0,该版本使用 JSON Schema 2020-12,以及 Swagger UI 5.0.0 及更高版本,所有内容都更加一致,示例包含在 JSON Schema 中。
Swagger UI 和 OpenAPI 特定的examples
¶
现在,由于 Swagger UI 不支持多个 JSON Schema 示例(截至 2023-08-26),用户没有办法在文档中显示多个示例。
为了解决这个问题,FastAPI 0.103.0
添加了支持,使用新的参数openapi_examples
声明相同的老 OpenAPI 特定的 examples
字段。🤓
总结¶
我过去说我不太喜欢历史... 看看我现在正在教授“技术历史”课。😅
简而言之,升级到 FastAPI 0.99.0 或更高版本,一切都会变得更加 简单、一致且直观,你不需要知道所有这些历史细节。😎