FastAPI 请求体(Request Body)实战指南:基于 Pydantic 模型完成数据接收、类型转换与自动校验
本篇技术指南聚焦 FastAPI 中请求体(Request Body)的完整使用方式:如何在路径操作函数中以 Pydantic 模型声明请求体、如何与路径参数和查询参数混用、FastAPI 在背后自动完成的 JSON 解析与校验逻辑,以及如何借助源码与测试验证这些行为。读完本文,你将能独立写出带类型安全、自动文档与编辑支持的生产级请求体接口。
请求体(Request Body)是什么
当客户端(例如浏览器)需要向你的 API 发送数据时,这些数据以 请求体(request body) 的形式提交;相应地,API 返回给客户端的数据被称为响应体(response body)。
需要明确两点基础认知:
- API 几乎总是需要发送响应体;
- 客户端则不一定每次都要发送请求体——有时客户端只请求某个路径,最多附带几个查询参数,而不携带请求体。
在 FastAPI 中,声明请求体使用 Pydantic 模型,你可以直接获得 Pydantic 的全部能力与收益(类型转换、数据校验、JSON Schema 生成等)。
注意(HTTP 方法选择)
要发送数据,应使用
POST(最常见)、PUT、DELETE或PATCH之一。在规范中,
GET请求携带请求体属于“行为未定义”,不过 FastAPI 出于对极复杂/极端场景的兼容仍然支持它。但由于这种做法不被推荐,Swagger UI 交互式文档在使用GET时不会展示请求体的说明,且中间的代理服务器可能也不支持。
第一步:声明请求体数据模型
导入 Pydantic 的 BaseModel
首先要从 pydantic 导入 BaseModel:
from fastapi import FastAPI
from pydantic import BaseModel
创建数据模型
然后声明一个继承自 BaseModel 的类作为数据模型,属性使用标准 Python 类型:
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
这段代码的完整示例位于 docs_src/body/tutorial001_py310.py。需要特别说明模型属性语义:
- 与声明查询参数时的规则一致:当模型属性带有默认值时,它不是必填的;否则就是必填的;
- 使用
None(并配合str | None、float | None这类可选类型注解)可以让字段“仅仅是可选”。
因此上面的模型描述的是一个 JSON "object"(等价于 Python dict),例如:
{
"name": "Foo",
"description": "An optional description",
"price": 45.2,
"tax": 3.5
}
由于 description 与 tax 是可选字段(默认值为 None),下面这个 JSON "object" 同样是合法的:
{
"name": "Foo",
"price": 45.2
}
第二步:把它声明为路径操作函数的参数
要把它加入 路径操作(path operation),只需像声明路径参数与查询参数那样声明,并把参数类型标注为刚创建的模型 Item:
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
完整代码见 docs_src/body/tutorial001_py310.py。这里没有写任何手动解析 JSON 的代码——仅凭这一个类型声明,任务就完成了。
一次类型声明,FastAPI 自动完成的全部工作
仅仅依靠上面的 Python 类型声明,FastAPI 就会自动:
- 读取请求体并将其解析为 JSON;
- 按需转换对应的类型(例如把 JSON 中的数字字符串
"50.5"转换成float); - 校验数据——如果数据无效,返回清晰友好的错误,精确指出错误的数据位置与内容;
- 把接收到的数据放入参数
item——由于在函数中声明类型为Item,所有属性及其类型都会获得完整的编辑器支持(补全、提示等); - 为模型生成 JSON Schema 定义,这些 Schema 可以复用于项目中任何合理的地方;
- 这些 Schema 会并入生成的 OpenAPI Schema,并被自动文档用户界面(UI)所使用。
源码与测试如何印证上述行为
在 FastAPI 源码中,请求体最终由 fastapi/params.py 中的 Body 字段信息类承载,其默认 media_type 为 application/json,也就是说请求体会按 JSON 媒体类型解析。而“读取并校验 JSON、返回 422”的行为,在仓库测试 tests/test_tutorial/test_body/test_tutorial001.py 中有着极为细致的覆盖,可直接作为验收依据:
- 类型转换:
{"name": "Foo", "price": "50.5"}中字符串形式的"50.5"会被转换为float类型的50.5,返回200与完整模型 JSON(见 test_tutorial001.py); - 缺少必填字段:
{"name": "Foo"}因缺少price返回422,错误信息中loc精确定位到["body", "price"],msg为Field required(见 test_tutorial001.py); - 非法类型值:
{"name": "Foo", "price": "twenty"}返回422,错误类型为float_parsing(见 test_tutorial001.py); - 残缺 JSON 正文:
{some broken json}这类无法解码的内容会返回422,错误类型为json_invalid,loc指向["body", 1](见 test_tutorial001.py); - 错误媒体类型:以
text/plain或application/geo+json-seq等非 JSON 类型提交会被拒绝,错误类型为model_attributes_type(见 test_tutorial001.py)。
这些测试同时表明:校验错误遵循 OpenAPI 的 ValidationError / HTTPValidationError 结构,loc 中的 "body" 前缀正好证明数据来源是请求体。
自动文档:模型 Schema 出现在交互式 API 文档中
你的模型 JSON Schema 会进入自动生成的 OpenAPI Schema,并展示在交互式 API 文档里。下图为文档首页展示的由模型生成的 Schema(含 Item 及 ValidationError、HTTPValidationError 错误模型):
而在每个使用到该模型的 路径操作 内部,同样会展示请求体示例、application/json 媒体类型与 200/422 响应说明,并支持 "Try it out" 在线调试:
当你需要验证自己写好的接口时,可启动应用后访问 /docs(Swagger UI)或 /redoc 查看上述界面。
编辑器支持:类型提示与自动补全
在编辑器里,函数内部你将随处获得类型提示与自动补全——如果你收到的是 dict 而不是 Pydantic 模型,这一切都不会发生:
同时,编辑器还能针对错误的类型操作给出错误检查。FastAPI 官方文档指出,这并非偶然——整个框架就是围绕这一设计构建的,并且在设计阶段、任何实现之前就进行了大量测试以确保能与所有主流编辑器协同工作,甚至为此对 Pydantic 本身做过修改。上述截图取自 Visual Studio Code;在 PyCharm 以及大多数其他 Python 编辑器中也能获得同样的支持。若使用 PyCharm,还可以搭配 Pydantic 的 PyCharm 插件,获得自动补全、类型检查、重构、搜索与检查等增强能力。
在函数内部使用模型对象
进入函数后,你可以直接访问模型对象的各个属性。下面的例子把模型转换为 dict(通过 Pydantic v2 的 model_dump()),并根据可选的 tax 字段动态计算含税价格:
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.model_dump()
if item.tax is not None:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
完整示例见 docs_src/body/tutorial002_py310.py。
请求体 + 路径参数:同时声明
可以同时声明路径参数与请求体。FastAPI 会自动识别:与路径参数匹配的函数参数从路径中取值,而声明为 Pydantic 模型的函数参数从请求体取值:
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, **item.model_dump()}
完整示例见 docs_src/body/tutorial003_py310.py。
请求体 + 路径参数 + 查询参数:三者同台
你也可以同时声明 请求体、路径参数 和 查询参数,FastAPI 会逐一识别并把数据取到正确的位置:
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
result = {"item_id": item_id, **item.model_dump()}
if q:
result.update({"q": q})
return result
完整示例见 docs_src/body/tutorial004_py310.py。对应的测试 tests/test_tutorial/test_body/test_tutorial004.py 验证了同时携带路径值 123、请求体四个字段与查询参数 q=somequery 时,返回结果完整包含 item_id、模型字段与 q。
函数参数如何被判定来源
当多个类型的参数混合出现时,FastAPI 按以下规则判定每个参数的来源:
- 如果参数同时出现在路径中,它会被用作路径参数;
- 如果参数是单一类型(如
int、float、str、bool等),它会被解释为查询参数; - 如果参数的类型是一个 Pydantic 模型,它会被解释为请求体。
关于可选参数 q 的判定细节
FastAPI 判断 q 非必填的依据不是类型注解 str | None,而是因为它有默认值 = None。不过加上类型注解依然有价值——它让你的编辑器提供更好的支持并及早发现错误。这一点已在 docs/en/docs/tutorial/body.md 的官方说明中强调。
从生成的 OpenAPI 模式看参数判定结果
在测试 tests/test_tutorial/test_body/test_tutorial004.py 的 OpenAPI 快照中可以看到:/items/{item_id} 的 PUT 操作中,item_id 出现在 parameters 且 in: path、required: true,q 出现在 parameters 且 in: query、required: false,而 Item 模型则作为 requestBody.content["application/json"].schema 且 required: true。请求体的必填性、三种数据来源的区分,都被精确地写入了 OpenAPI 定义,这也是自动文档能正确渲染的前提。
不想用 Pydantic?使用 Body 参数
如果不希望使用 Pydantic 模型,也可以直接使用 Body 参数把单一类型的值放入请求体。详见文档 Body - Multiple Parameters: Singular values in body,那里介绍了如何在 body 中携带单个标量值及其与模型共存时的写法。
小结与后续学习路径
请求体的核心心智模型是:“声明 Pydantic 模型类 → 作为路径操作函数参数的类型注解”,其余(JSON 读取、类型转换、校验、错误响应、Schema 生成、编辑器支持)都由 FastAPI 自动完成。本文对应的原始教程位于 docs/en/docs/tutorial/body.md,可运行示例集中在 docs_src/body/,行为验证测试位于 tests/test_tutorial/test_body/。
在掌握单一模型请求体后,建议继续深入学习以下进阶主题(均为 FastAPI 官方教程同系列内容):
- 请求体中的字段级约束与元数据声明(见 docs/en/docs/tutorial/body-fields.md);
- 请求体与多个参数、
Body嵌入模式的配合(见 docs/en/docs/tutorial/body-multiple-params.md); - 嵌套模型、列表与复杂 JSON 结构(见 docs/en/docs/tutorial/body-nested-models.md);
- 数据模型校验的底层能力(可进一步阅读 fastapi/params.py 中
Body类与FieldInfo的参数体系)。
掌握这些之后,无论是 REST 资源写入、批量提交还是复杂嵌套的业务数据结构,你都能用最少的样板代码写出类型安全且自文档化的接口。
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 StartedRust0624
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


