跳到内容

声明请求示例数据

您可以声明应用程序可以接收的数据示例。

以下是一些方法。

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 中,您将使用内部类 Configschema_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 中添加的额外信息。

examplesBody

在这里,我们传递包含 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
  • externalValuevalue 的替代方案,一个指向示例的 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 SchemaOpenAPI 标准的非常技术性的细节。

如果上面的想法对你已经起作用,那可能就足够了,你可能不需要这些细节,可以随意跳过它们。

在 OpenAPI 3.1.0 之前,OpenAPI 使用了旧版且修改过的 JSON Schema

JSON Schema 没有examples,因此 OpenAPI 为其自己的修改版本添加了自己的example 字段。

OpenAPI 还将exampleexamples 字段添加到规范的其他部分,

信息

这个旧的 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_extraField(examples=["something"]) 在 Pydantic 模型中添加examples 时,该示例将添加到该 Pydantic 模型的 JSON Schema 中。

然后,Pydantic 模型的 JSON Schema 将包含在 API 的 OpenAPI 中,然后它将在文档 UI 中使用。

在 FastAPI 0.99.0 之前的版本中(0.99.0 及更高版本使用更新的 OpenAPI 3.1.0),当你使用exampleexamples 与其他任何实用程序(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 或更高版本,一切都会变得更加 简单、一致且直观,你不需要知道所有这些历史细节。😎