FastAPI 声明请求示例数据全指南:model_config、Field(examples) 与 openapi_examples
本篇技术指南以 docs/fr/docs/tutorial/schema-extra-example.md(英文原文见 docs/en/docs/tutorial/schema-extra-example.md)为核心脉络,系统讲解如何在 FastAPI 中为接口声明“请求示例数据”:既可以在 Pydantic 模型层通过 model_config / Field() 让示例进入 JSON Schema,也可以通过 Path()、Query()、Body() 等参数工具直接携带示例;并深入剖析 examples(JSON Schema 级)与 openapi_examples(OpenAPI 级)这两套字段的区别、演进历史及在 /docs 交互文档中的实际效果。读完本文,你将能根据需求为任意路径操作或数据模型配置"可复制、可演示、多版本可切换"的请求示例。
所有演示代码均取自仓库中的 docs_src/schema_extra_example/ 目录(Python 3.10+ 语法版本,文件后缀 _py310),并配套说明底层实现依据,可直接运行验证。
总览:声明示例数据的三种入口
FastAPI 中“声明请求示例数据”可以归结为三种方式,对应不同的生成产物与作用范围:
- 模型级:在 Pydantic 模型的
model_config中设置"json_schema_extra",或在Field()中传入examples=[...],数据会原样进入该模型产出的 JSON Schema; - 参数级(JSON Schema 内):在使用
Path()、Query()、Header()、Cookie()、Body()、Form()、File()时传入examples=[...],示例进入这些参数的 JSON Schema 并随 OpenAPI 输出; - 参数级(OpenAPI 路径操作级):同样在上述七种参数工具上使用
openapi_examples={...},示例被写入 OpenAPI 规范中 每个路径操作(path operation) 的examples字段,从而让 Swagger UI 提供多个示例的下拉切换。
下文先讲模型级与参数级的基础用法,再深入 openapi_examples 与标准演进的技术细节。
在 Pydantic 模型中用 model_config 扩展 JSON Schema
你可以为 Pydantic 模型声明 examples,它们会被添加到生成的 JSON Schema 中。完整示例见 tutorial001_py310.py:
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
要点如下:
- 这些额外信息会被**原样(as-is)**加入该模型输出的 JSON Schema,并最终用于 API 文档(
/docs)展示; model_config是 Pydantic v2 的类级配置属性,接受一个dict;其中的"json_schema_extra"键可以放入任意你希望出现在生成 JSON Schema 中的数据,examples只是最常见的一种;- 这种手法同样适用于扩展 JSON Schema 加入自定义元数据,例如为前端用户界面补充标记信息等,不局限于示例数据。
注意:OpenAPI 3.1.0(自 FastAPI 0.99.0 起使用)原生支持
examples,它是 JSON Schema 标准的一部分。在此之前的版本只支持单值关键字example。OpenAPI 3.1.0 仍然兼容example,但它已被标记为弃用,且不属于 JSON Schema 标准,因此官方建议将example迁移到examples。
使用 Field() 的额外参数声明字段级示例
当使用 Pydantic 的 Field() 时,也可以在每个字段上声明自己的 examples,见 tutorial002_py310.py:
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
与模型级方式相比,Field(examples=[...]) 把示例细分到了字段维度:每个字段可独立给出"该字段看起来像什么",最终同样合并到模型对应的 JSON Schema 中。注意 examples 参数是一个 list,即使只有一个示例也要写成列表形式。
在七种参数工具上声明 JSON Schema 级 examples
除了模型内部,使用以下任一 FastAPI 参数工具时,也可以声明一组 examples,它们会被加入 OpenAPI 内部对应参数的 JSON Schema:
Path()Query()Header()Cookie()Body()Form()File()
Body() 携带单个 examples
以请求体为例,给 Body() 传入包含期望数据的 examples,见 tutorial003_an_py310.py:
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
使用 Annotated[...] 将 Body(...) 的元数据绑定到参数上是目前推荐的写法。采用上述任意方式后,/docs 界面中的请求体会展示该示例值,效果见下图:
Body() 携带多个 examples
自然也可以传入多个示例,见 tutorial004_an_py310.py:
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
这里的多个示例会被并入该请求体数据内部的 JSON Schema(注意示例本身并不代表数据一定合法,例如上例中的 "price": "thirty five point four" 是故意用来演示非法数据的)。需要特别说明的是:截至本文写作时(原文记录为 2023-08-26),负责渲染文档界面的 Swagger UI 尚不支持在 JSON Schema 层面展示多个示例——它只会显示其中一个。解决这个限制的方法,就是下面介绍的 OpenAPI 特有的 openapi_examples。
用 openapi_examples 声明 OpenAPI 级多示例
在 JSON Schema 支持 examples 之前,OpenAPI 规范就已经拥有一个同样名为 examples、但语义不同的字段。
这个 OpenAPI 特有的 examples 位于规范的另一处:它挂在每个路径操作(path operation)的细节里,而不是嵌在每个 JSON Schema 内部。由于 Swagger UI 早已支持该字段,因此可以用它来在文档界面中展示并切换多个示例。
它的数据结构是一个 dict(而不是 list):外层 键 标识每个示例,值 是另一个 dict,其中的可选字段如下:
summary:示例的简短描述;description:较长的描述,可包含 Markdown 文本;value:实际展示的示例数据,例如一个dict;externalValue:value的替代项,是一个指向示例内容的 URL;不过它可能不如value那样被众多工具支持。
FastAPI 中通过参数 openapi_examples 声明它,可用于:Path()、Query()、Header()、Cookie()、Body()、Form()、File()。完整示例见 tutorial005_an_py310.py:
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
为 Body() 添加 openapi_examples 后,/docs 界面会渲染出可切换的多示例下拉框(示例名称取自外层键,展示内容取自各值中的 summary / description / value):
底层实现依据
在仓库源码中可以看到这套设计的直接实现:
- 在 fastapi/param_functions.py 中,
Path/Query/Header/Cookie/Body/Form/File等函数均接受参数examples: list[Any] | None与openapi_examples: dict[str, Example] | None;同时example: Any参数被标记为deprecated,其弃用说明为 "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, although still supported. Use examples instead."(见该文件中每个参数工具的注解区块); - 在 fastapi/openapi/utils.py 生成 OpenAPI 时:对于查询/路径等参数,
openapi_examples会写入参数对象顶层的parameter["examples"](第 219-224 行);对于请求体,则写入request_media_content["examples"](第 256-261 行),并优先于旧的example字段——这正是“OpenAPI 特有示例位于 JSON Schema 之外”的实现落点; - 对应的行为测试集中在 tests/test_openapi_examples.py 中,可据此验证上述输出结构。
技术细节:一段 OpenAPI 与 JSON Schema 的演进历史
如果你已经在使用 FastAPI 0.99.0 及以上版本,以下内容可以跳过——它主要面向旧版本(尚未引入 OpenAPI 3.1.0 之前)的兼容问题,可看作一段简短的 OpenAPI / JSON Schema 历史课,有助于你理解为什么当前 API 中会同时存在 examples 与 openapi_examples 两种写法。
警告:以下是关于 JSON Schema 与 OpenAPI 标准的高度技术性细节。如果上面的用法已经满足需求,可以放心跳过本节。
演进起点:OpenAPI 自带的 example
在 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参数,自 FastAPI0.103.0起被重命名为openapi_examples。
JSON Schema 的 examples 字段
随后,JSON Schema 在新版规范(2019-09 draft 起引入校验关键字)中增加了 examples 字段;再后来,全新的 OpenAPI 3.1.0 基于包含该字段的最新版 JSON Schema 2020-12 构建。新的 examples 字段由此取代了旧的单值自定义字段 example,后者现在处于弃用状态。
注意一个容易混淆的差异:JSON Schema 中的 examples 仅仅是一个 list(一列示例值),并不是像 OpenAPI 其他位置那样带 summary/description 元数据的 dict。
补充:即便 OpenAPI 3.1.0 发布并带来了与 JSON Schema 更简洁的整合,负责渲染自动文档的 Swagger UI 在一段时间内仍不支持 OpenAPI 3.1.0(直到 Swagger UI 5.0.0 起才支持)。正因如此,FastAPI 0.99.0 之前的版本一直使用低于 3.1.0 的 OpenAPI 版本。
不同写法在 Pydantic / FastAPI 中的归宿
- 在 Pydantic 模型内通过
schema_extra(或 v2 的json_schema_extra)或Field(examples=[...])添加的examples,会被写入该 Pydantic 模型的 JSON Schema;这个模型 JSON Schema 又会被嵌入 API 的 OpenAPI 文档,并在文档界面中使用。 - 在 FastAPI 0.99.0 之前的版本中,通过
Query()、Body()等参数工具使用example或examples时,示例不会被加入描述该数据的 JSON Schema(甚至不属于 OpenAPI 自己的 JSON Schema 变体),而是被直接写入 OpenAPI 中路径操作的声明处(即所有使用 JSON Schema 的区域之外)。 - 从 FastAPI 0.99.0 起改用 OpenAPI 3.1.0(基于 JSON Schema 2020-12),加上 Swagger UI 5.0.0+ 的配合,整体趋于一致:示例被纳入 JSON Schema 之中。
为什么还需要 openapi_examples
尽管现代 FastAPI 已把参数级 examples 并入 JSON Schema,但 Swagger UI 截至 2023-08-26 仍不支持在文档界面展示“JSON Schema 中的多个示例”,因此用户缺少一条展示多示例的途径。为解决这一缺口,FastAPI 0.103.0 新增了 openapi_examples 参数,用于声明同一份旧版 OpenAPI 特有的 examples 字段——这正是上文第 4 节内容存在的根本原因。在 fastapi/params.py 中可以看到,参数基类 Param 构造器接收 openapi_examples: dict[str, Example] | None 并保存在 self.openapi_examples,随后由 OpenAPI 生成逻辑按"路径操作级"字段输出。
小结
归根结底,官方给出的最简结论是:升级到 FastAPI 0.99.0 或更高版本,配合较新的 Swagger UI,示例数据的处理会更加简单、一致、直观,大部分历史细节你都不必再关心;此时只需按用途选择:
- 想让示例进入模型/字段的 JSON Schema,用
model_config["json_schema_extra"]或Field(examples=[...]); - 想让单个示例进入具体参数的 JSON Schema,在
Body()等参数工具上传examples=[...]; - 想获得多示例下拉切换的文档体验,使用参数工具上的
openapi_examples={...}。
另外提醒:当前仓库示例代码以 Annotated 结合 Python 3.10+ 类型语法编写(str | None),运行前请确认解释器版本满足要求,相关可直接运行的源码均可在 docs_src/schema_extra_example/ 目录中找到,对应的行为断言可参考 tests/test_openapi_examples.py。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00

