FastAPI 声明请求示例数据:JSON Schema examples 与 openapi_examples 的完整用法与原理
如果你的 API 需要让前端、接口测试人员或下游调用方「一眼就知道该往 Body 里传什么」,那么**请求示例数据(Request Example Data)**就是最直接的沟通桥梁。本指南围绕 FastAPI 官方教程「Declare Request Example Data」(见 docs/en/docs/tutorial/schema-extra-example.md)展开,系统讲解在 Pydantic 模型、字段级 Field() 以及 Path() / Query() / Header() / Cookie() / Body() / Form() / File() 等参数工具上声明 examples 的完整方法,并深入剖析 examples 与 OpenAPI 专用 openapi_examples 两条路径的差异。读完你将能够:在自动生成的 /docs 接口文档中展示直观的单/多示例,在 OpenAPI 输出里精确控制示例的归属位置(JSON Schema 内 vs path operation 级),并理解 FastAPI 0.99.0 引入 OpenAPI 3.1.0 之后整套示例机制演进的前因后果。
三条主要声明路径一览
FastAPI 支持在三个不同层级为请求数据声明示例,它们最终都会体现到自动生成的 OpenAPI / JSON Schema 与交互式 API 文档中:
- Pydantic 模型层:通过模型配置
model_config["json_schema_extra"]写入整个模型的额外 JSON Schema 数据(含examples)。 - 字段层:通过
Field(examples=[...])为单个模型字段声明示例。 - 接口参数层:通过
Body()等参数工具上的examples或openapi_examples为某个路径操作声明请求数据示例。
下文将逐一演示。配套可运行源码全部位于仓库 docs_src/schema_extra_example/ 目录下,对应 tutorial001~tutorial005 的 Python 3.10 版本文件。
在 Pydantic 模型中追加 JSON Schema 额外数据(json_schema_extra)
第一种方式是在 Pydantic 模型中声明 examples,它会被原样追加到该模型生成的 JSON Schema 中,并随之进入 API 文档。核心做法是使用 Pydantic 的 model_config 属性(接受一个 dict),把任意想要出现在 JSON Schema 里的附加信息放进键 "json_schema_extra",其中自然可以包含 examples。完整示例见 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
关于该写法的几个要点:
- 数据原样透传:
json_schema_extra中的内容会被不加修改地并入 Pydantic 模型生成的 JSON Schema(Item对应的#/components/schemas/Item),FastAPI 生成 OpenAPI 时引用这份 Schema,文档 UI 即可读取其中的examples。 - 不只是示例:这一技巧同样可用于扩展 JSON Schema、加入任何自定义附加信息,例如为前端界面补充元数据。
json_schema_extra的值既可以像上面一样是一个dict,也可以是一个「入参为生成中的 schema、返回新的 schema」的 callable(由 Pydantic 负责调用)。 - API 兼容提示:模型级
examples之所以能正常工作,是因为 FastAPI 0.99.0 起生成的 OpenAPI 版本为 3.1.0,而 OpenAPI 3.1.0 采用的 JSON Schema 2020-12 标准本身就包含examples关键字(详见文末「技术细节」一节)。 - 若遇到 Pydantic v1 项目,等价写法是把同样内容放进
class Config: json_schema_extra = {...};v2 下则统一使用model_config。仓库内 docs_src/pydantic_v1_in_v2/ 有 Pydantic v1 语法在 v2 环境下迁移的对照示例可供参考。
用 Field() 为单个字段声明 examples
当希望按字段粒度逐个声明示例时,可以在模型字段的类型注解中使用 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
与模型级配置相比:
- 这里每个字段的
examples(注意是列表)会进入 JSON Schema 中对应properties下的examples,属于字段维度的声明,不会互相干扰。 examples与字段的default、校验规则(gt、max_length等)完全解耦,可以分开指定,不影响校验行为。- 这种字段级示例在文档 UI 中会作为「该字段的推荐取值」提示呈现,适合字段含义不直观、需要给调用方「抄作业」的场景。
在接口参数工具上声明 examples(写入参数自身的 JSON Schema)
examples 同样可以用在 FastAPI 的任何参数工具上,它们分别是:
Path():路径参数Query():查询参数Header():请求头Cookie():CookieBody():请求体Form():表单字段File():上传文件
在这些工具上声明的 examples 会被加入它们在 OpenAPI 内部的 JSON Schema。下面以 Body() 为例演示。
Body 携带单个示例
先定义一个 Item 模型,然后在接口签名中通过 Body(examples=[...]) 给出请求体应包含的数据示例。以下为基于 Annotated 的写法,见 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
FastAPI 同时支持不使用 Annotated、直接把 Body(...) 作为默认值的等价写法,见 tutorial003_py310.py。两种风格效果一致,选择其一即可(新版项目建议优先 Annotated)。
文档 UI 中的效果
采用上述任意一种方式后,访问 /docs,请求体区域会展示已声明的示例,Swagger UI 会为请求体渲染出可直接试用的样例。其界面效果如下(该图为 FastAPI 官方文档教程页截图):
Body 携带多个示例
examples 本身是列表,因此可以一次传入多个示例。见 tutorial004_an_py310.py(非 Annotated 版本见 tutorial004_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
上面三个示例刻意设计了三种形态,非常有教学价值:
Foo:字段齐全的标准合法请求;Bar:price传的是字符串"35.4",用来演示 FastAPI/Pydantic 能把字符串自动转换成数值;Baz:price传了"thirty five point four",这是故意给出的非法数据,用于向调用方演示「传错会收到校验错误」。
需要注意:多示例会被写入该请求体数据在 OpenAPI 内部的 JSON Schema 中。而截至教程撰写时点(文档标注 2023-08-26),负责渲染文档 UI 的 Swagger UI 尚不支持渲染 JSON Schema 内的多示例——也就是说,如果只依赖这种写法,界面上很可能看不到多个示例切换。要解决这一限制,请继续看下一节「OpenAPI 专用 examples」。
OpenAPI 专用 examples 与 openapi_examples 参数
它与 JSON Schema examples 的区别
早在 JSON Schema 引入 examples 之前,OpenAPI 就自己定义过一个同样叫 examples 的字段。这个 OpenAPI 专用 examples 的位置与上一节完全不同:它不在任何 JSON Schema 内部,而是直接挂在每个 path operation(路径操作)的细节区域。具体而言,OpenAPI 3.1 规范中:
Parameter Object的examples字段 —— 对应 FastAPI 的Path()、Query()、Header()、Cookie();Request Body Object内content的Media Type Object上的examples字段 —— 对应 FastAPI 的Body()、Form()、File()。
它的数据形态也和 JSON Schema 版不同:是一个字典(dict)而非列表,每个 key 是一个示例名,value 是携带额外元数据的示例描述对象。Swagger UI 对这类 OpenAPI 专用 examples 支持已久,因此用它才能在文档 UI 中切换展示多个示例。
openapi_examples 参数及其四个子字段
FastAPI 从 0.103.0 开始,用新参数 openapi_examples 承接上述 OpenAPI 专用 examples(此前旧文档称之为 examples,现已改名)。它适用于与上一节相同的 7 个参数工具:Path()、Query()、Header()、Cookie()、Body()、Form()、File()。
openapi_examples 的值是一个 dict,key 用于标识每个示例,每个 value 又是另一个 dict,其中可包含以下字段:
| 字段 | 含义 | 说明 |
|---|---|---|
summary |
示例的简短说明 | 用于在 UI 中标识该示例,例如 "A normal example" |
description |
长描述 | 支持 Markdown 文本,可对示例做详细解释 |
value |
示例的真实数据 | 通常是一个 dict,即实际展示、可点击填充到请求体的内容 |
externalValue |
示例的外部 URL | value 的替代方案,指向存放示例内容的链接;不过支持它的工具没有 value 那么普遍 |
用法示例
以下代码在 Body() 上声明了三个带「场景化说明」的 OpenAPI 专用示例,见 tutorial005_an_py310.py(非 Annotated 版本见 tutorial005_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
三个示例分别对应「正常请求」「字符串价格被自动转换」「非法数据被校验拦截」,配合 summary 与支持 Markdown 的 description,能把每种请求的语义讲解得非常清楚,非常适合用于团队协作与对外 API 文档。
OpenAPI 示例在文档 UI 中的效果
为 Body() 添加 openapi_examples 后,/docs 页面会以可切换示例的方式渲染请求体,用户可点击不同示例名并一键填充到请求内容。效果如下:
源码印证:examples 如何被写进 OpenAPI
上述声明最终都会在生成 OpenAPI 时被落地。可以在本仓库 fastapi/openapi/utils.py 中看到精确的实现逻辑:
路径/查询/请求头/Cookie 参数(对应 Path/Query/Header/Cookie)位于 get_openapi_path 构造 parameters 的过程里,fastapi/openapi/utils.py:
openapi_examples = getattr(field_info, "openapi_examples", None)
example = getattr(field_info, "example", None)
if openapi_examples:
parameter["examples"] = jsonable_encoder(openapi_examples)
elif example is not _Unset:
parameter["example"] = jsonable_encoder(example)
请求体(对应 Body/Form/File)则在 get_openapi_operation_request_body 中,把示例放进 content 下媒体类型的映射里,fastapi/openapi/utils.py:
request_media_content: dict[str, Any] = {"schema": body_schema}
if field_info.openapi_examples:
request_media_content["examples"] = jsonable_encoder(
field_info.openapi_examples
)
elif field_info.example is not _Unset:
request_media_content["example"] = jsonable_encoder(field_info.example)
两点可以注意:
- 优先级明确:
openapi_examples存在时优先写入(落到examples);否则回退到旧的单一example字段。这从代码层面印证了官方「推荐用examples替代旧的example」的取向。 - 参数定义源头:
openapi_examples与json_schema_extra参数在Path/Query/Header/Cookie/Body/Form/File各自的构造函数中均有声明(可参考 fastapi/param_functions.py 中openapi_examples与json_schema_extra的出现位置),与上文列出的 7 个工具一一对应。
模型级声明走的是另一条链路:Pydantic 依据 model_config["json_schema_extra"] 或 Field(examples=...) 生成模型 JSON Schema(仓库兼容层 fastapi/_compat/v2.py 中可见 "json_schema_extra": None 之类的默认配置项),FastAPI 再把模型 Schema 嵌入 OpenAPI 的 components/schemas,文档 UI 读取后渲染。仓库中的 tests/test_schema_extra_examples.py 等测试对这两种 examples 的输出结果均有断言,可作为改动后回归验证的入口。
技术细节:JSON Schema 与 OpenAPI 的示例演进史
如果你正在使用 FastAPI 0.99.0 及以上版本,前面几节的内容已经足够,本节属于「历史课」,主要面向老版本用户或想彻底理解标准差异的读者。
OpenAPI 3.1.0 之前:各自为政的 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()。
这就是两套同名词条长期并存的根源。
JSON Schema 的 examples 与 OpenAPI 3.1.0
随后 JSON Schema 在自己的新版本规范(自 draft 2019-09 起引入)中增加了 examples 字段,而基于 JSON Schema 2020-12 的全新 OpenAPI 3.1.0 因此天然继承了该字段。在新规范下,JSON Schema 内的 examples 只是一个示例值的列表(list),没有额外的元数据字典包装。
examples 与旧 example 同时存在时,新的 examples 拥有更高优先级,旧的单值 example 字段虽仍被 OpenAPI 3.1.0 支持,但已标记为弃用且不属于 JSON Schema 标准,官方鼓励将 example 迁移为 examples。
FastAPI 各版本与此的对应关系
- OpenAPI 3.1.0 正式发布后的一段时间里,Swagger UI 并不支持 OpenAPI 3.1.0(直到 Swagger UI 5.0.0 起才支持)。因此 FastAPI 0.99.0 之前的版本仍输出低于 3.1.0 的 OpenAPI。
- FastAPI 0.99.0 起改用更新的 OpenAPI 3.1.0(即 JSON Schema 2020-12),配合 Swagger UI 5.0.0+,
examples得以统一收录进 JSON Schema,整条链路更加一致。 - Swagger UI 仍不渲染 JSON Schema 内的多个示例(截至 2023-08-26),为了在文档中展示多个示例,FastAPI 0.103.0 新增了
openapi_examples参数,用来声明那组挂在 path operation / media type 层级的 OpenAPI 专用examples。
演进前后示例落点的差异
- 旧版本中,用
Query()、Body()等工具声明example/examples时,内容不会进入描述该数据的 JSON Schema(甚至也不在 OpenAPI 自己的 JSON Schema 版本里),而是直接写入 OpenAPI 中该 path operation 的声明区域(即所有使用 JSON Schema 的区块之外)。 - 新版本(FastAPI 0.99.0+)中,一切趋于一致:Pydantic 模型内的
examples进入模型 JSON Schema;Body()等工具上的 JSON Schemaexamples进入参数对应的 schema;openapi_examples则保留在 OpenAPI 操作级区域供 UI 做多示例切换。
实践建议与小结
| 场景 | 推荐做法 |
|---|---|
| 想让整个模型在文档中展示推荐请求体 | 模型上配置 model_config["json_schema_extra"]["examples"] |
| 想按字段逐一给出示例取值 | 字段使用 Field(examples=[...]) |
| 只想给某个接口的请求体/参数配一个示例 | 参数工具(Body() 等)上传 examples=[{...}] |
| 想在文档 UI 中切换展示多个示例并附说明 | 参数工具上传 openapi_examples={...},配合 summary / description / value |
总的原则是:升级到 FastAPI 0.99.0 及以上,examples 的语义在各层保持一致且直观;若需要在 Swagger UI 中展示多示例,再使用 0.103.0+ 引入的 openapi_examples。示例声明只影响文档与 Schema 输出,不改变任何校验行为,因此可以放心为「正常请求」「边界数据」乃至「故意非法」的场景各配一份,帮助 API 使用方把请求一次写对。
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 StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00

