首页
/ FastAPI 请求体(Request Body)实战指南:基于 Pydantic 模型声明与校验请求数据

FastAPI 请求体(Request Body)实战指南:基于 Pydantic 模型声明与校验请求数据

2026-09-07 22:35:09作者:廉彬冶Miranda

FastAPI 的请求体(Request Body)功能,让你可以用一个 Python 类型标注就能完成 JSON 数据的读取、类型转换、数据校验与自动化文档生成。本指南以 body 教程 为主线,结合仓库内 docs_src/body 的示例源码与 tests/test_tutorial/test_body 测试用例,系统讲解如何在 FastAPI 中声明并处理请求体。学完你将掌握:使用 Pydantic BaseModel 定义数据模型、将模型与 path/query 参数混合声明、理解 FastAPI 的参数识别规则,以及模型自动生成 OpenAPI Schema 背后的实现细节。

什么是 Request Body

当客户端(比如浏览器)需要向 API 发送数据时,数据以 request body(请求体) 的形式发送;而 API 返回给客户端的数据则称为 response body(响应体)

  • request body:客户端发送给 API 的数据;
  • response body:API 返回给客户端的数据。

API 几乎总是需要返回 response body,但客户端并不总是需要发送 request body——有时客户端仅仅请求一个路径,最多携带几个 query 参数,并不发送任何 body。

在 FastAPI 中声明 request body,使用的是 Pydantic 模型,可以完整继承 Pydantic 的全部能力与收益。

发送数据应使用的 HTTP 方法

官方教程特别强调:要发送数据,应使用 POST(最常见)、PUTDELETEPATCH 中的一种。

  • GET 请求中携带 body,其行为在 HTTP 规范中属于 undefined(未定义)状态。FastAPI 出于兼容性仍然支持这种用法,但仅面向非常复杂/极端的场景;
  • 由于该用法本身被建议避免,Swagger UI 交互式文档在使用 GET不会为 body 展示文档说明,中间的代理服务器也可能不支持这种请求。

核心示例:声明一个携带 JSON 请求体的接口

这一部分对应的完整示例位于仓库 docs_src/body/tutorial001_py310.py,它将从零到一演示声明请求体的三个步骤。

第一步:导入 Pydantic 的 BaseModel

from pydantic import BaseModel

第二步:创建数据模型

将数据模型声明为一个继承自 BaseModel 的类,属性使用标准 Python 类型:

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

这里与声明 query 参数时同样的规则生效:当某个模型属性带有默认值时,它不是必填的;否则它就是必填的。要让某个属性仅作 optional 处理,将默认值设为 None

因此,上面的 Item 模型声明的就是一个类似如下的 JSON "object"(等价于 Python dict):

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

由于 descriptiontax 是可选的(默认值为 None),下面的 JSON "object" 同样是合法的请求体:

{
    "name": "Foo",
    "price": 45.2
}

技术细节:description: str | None = None 中的类型标注与默认值分工不同。在 Pydantic v2(也是本仓库当前使用的版本)中,str | None 描述的是字段可以取的类型(string 或 null),而 = None 才决定字段是否必填。测试文件 tests/test_tutorial/test_body/test_tutorial004.py 中的 test_put_only_required 验证了仅发送必填字段 {"name": "Foo", "price": 50.1} 时请求成功,且缺省字段以 None 出现在响应中。

第三步:在路径操作中将其声明为参数

把模型添加进你的 path operation,声明方式与你之前声明 path 参数和 query 参数完全相同——直接把它作为函数参数,并把类型声明为 Item

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

FastAPI 会自动做哪些事

仅仅依靠上面这行 Python 类型声明,FastAPI 就会自动完成:

  1. 将请求体作为 JSON 读取
  2. 执行类型转换(必要时);
  3. 校验数据——如果数据无效,会返回一个友好、清晰的错误响应,精确指出错误数据所在的位置与具体内容;
  4. 把接收到的数据交给参数 item——因为你在函数中把它声明为 Item 类型,IDE 会对它的所有属性及属性类型提供完整的编辑器支持(自动补全等);
  5. 为你的模型生成 JSON Schema 定义——如果对你的项目有意义,这些 Schema 可以在其他任何地方复用;
  6. 将这些 Schema 纳入生成的 OpenAPI Schema,并供自动文档 UI 使用。

参数识别规则:FastAPI 如何区分 body、path 与 query

在 FastAPI 中,函数参数的数据来源完全由类型标注和声明位置决定。以一个同时包含 path 参数、query 参数和 Pydantic 模型的接口为例(完整源码见 docs_src/body/tutorial004_py310.py):

@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

FastAPI 会按如下规则识别每一个函数参数:

  • 如果该参数同时声明在路径(path)中,则作为 path 参数使用;
  • 如果参数是单一类型(singular type),例如 intfloatstrbool 等,则被解释为 query 参数
  • 如果参数被声明为 Pydantic 模型的类型,则被解释为 request body

这一点在单元测试 tests/test_tutorial/test_body/test_tutorial004.pytest_openapi_schema 中有精确的落点:生成出的 OpenAPI 3.1.0 Schema 中,item_id 出现在 parametersin: "path"required: Trueq 出现在 parametersin: "query"required: False;而 Item 模型则被挂在 requestBody.content["application/json"].schema$ref 上,同时 components.schemas.Item 中的 required 数组精确为 ["name", "price"]——可见这一识别与拆分发生在框架层并被完整序列化进了 OpenAPI 文档。

关于可选参数的常见误区

在上面的例子中,FastAPI 之所以知道 q 的值不是必填的,是因为它的默认值是 = None而不是因为标注了 str | None

官方文档明确:str | None 这种类型标注并不被 FastAPI 用来判断值是否必填;它判断"非必填"的依据是存在默认值 = None。不过,添加类型标注仍然有价值——它让编辑器提供更好的支持并帮助你检测错误。

请求体校验失败的实战表现

当一个必填字段缺失时,FastAPI 会返回 422 Unprocessable Entity 以及结构化的错误明细。test_put_with_no_data 测试对 /items/123 发送空对象 {},得到的响应为:

{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "name"],
      "msg": "Field required",
      "input": {}
    },
    {
      "type": "missing",
      "loc": ["body", "price"],
      "msg": "Field required",
      "input": {}
    }
  ]
}

注意 loc 字段从 "body" 开始,精确标注了缺失字段位于请求体中的哪个位置——这正是"清晰错误"的具体体现,且该错误模型(ValidationError / HTTPValidationError)也会被自动写入 OpenAPI 的 components.schemas

自动文档:模型 Schema 自动进入交互式 API 文档

你定义的模型 JSON Schema 会自动成为 OpenAPI 生成 Schema 的一部分,并显示在交互式 API 文档中:

FastAPI 交互式文档中自动展示的 Item 模型 Schema,标出必填字段 name 与 price 及可选的 description 与 tax

这些 Schema 也会被用在 API 文档中每一个需要它们的 path operation 内部,展示该接口期望接收的请求体结构:

API 文档中 path operation 内部的请求体 Schema 展示

由于 body 与 OpenAPI 的深度绑定,你不仅可以查看文档,还可以直接调用 /openapi.json 获取机器可读的完整 Schema——这正是生成客户端 SDK、做契约测试的基础。

编辑器支持:类型提示、自动补全与错误检查

在你的编辑器里,函数内部随处都能得到类型提示(type hints)和自动补全(completion)。如果你接收的是一个普通 dict 而不是 Pydantic 模型,这些支持将完全不存在

# 若 item 是 dict,item.name 无法得到补全与类型推断
# 声明为 Item 后,item.name / item.price / item.tax 全部拥有类型信息

编辑器还会对错误的类型操作给出错误检查。这不是巧合——整个 FastAPI 框架就是围绕"类型驱动"这一设计理念构建的,甚至在设计阶段、任何实现落地之前就对这一机制进行了充分测试,以确保它在各类编辑器中都能正常工作;为此 Pydantic 本身也做出过相应改动。上述效果在 Visual Studio Code、PyCharm 及大多数主流 Python 编辑器中都能获得。

技巧:如果你使用 PyCharm,可以安装 Pydantic PyCharm 插件,它针对 Pydantic 模型增强了编辑器支持,包括自动补全、类型检查、重构、搜索与代码检查(inspections)。

在函数体内使用模型对象

在函数内部,你可以直接访问模型对象的全部属性。一个更贴近业务的用法是结合 Pydantic v2 的 model_dump() 把模型转为字典,再基于可选字段追加计算逻辑,完整源码见 docs_src/body/tutorial002_py310.py

@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

这里 item.tax is not None 的判空逻辑展示了如何利用"可选字段默认 None"这一约定,仅在客户端显式传入 tax 时才计算含税价格。

Request Body 与 Path 参数同时声明

你可以在同一个接口中同时声明 path 参数与请求体(示例源码见 docs_src/body/tutorial003_py310.py):

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.model_dump()}

FastAPI 会自动识别:凡是与 path 中已声明参数同名的函数参数,从 path 中取值;凡是声明为 Pydantic 模型的函数参数,从 request body 中取值。两者互不干扰、可同时使用。

Request Body + Path + Query 三参数并存

更进一步,你可以在同一接口中同时声明 bodypathquery 三类参数(完整源码见 docs_src/body/tutorial004_py310.py):

@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

FastAPI 会识别出每一个参数,并从正确的位置获取数据。测试用例 test_put_all(见 tests/test_tutorial/test_body/test_tutorial004.py)一次性验证了三种来源数据的正确合并:请求行中 item_id=123 取自路径、name/price 等取自 JSON body、q="somequery" 取自 query string,最终响应按 {"item_id": 123, ..., "q": "somequery"} 返回。

一个值得留意的实现细节是:即便客户端请求体只包含部分字段,Pydantic 模型的缺省属性在经 model_dump() 转换后仍会以 None 保留在字典中,因此上述返回结构是确定且可预期的。

不使用 Pydantic 时的替代方案

如果你不想(或不方便)使用 Pydantic 模型,FastAPI 还提供了 Body 参数,用于把单个值放入请求体中。详见仓库文档 Body - Multiple Parameters: Singular values in body

结合源码验证与运行建议

你可以在当前仓库中完整复现并验证本文涉及的全部行为:

  • 源码示例:docs_src/body 目录下的 tutorial001_py310.pytutorial004_py310.py,对应本指南的四个递进场景;
  • 测试用例:tests/test_tutorial/test_body 目录,覆盖合法请求、仅必填字段、空 body 的 422 校验错误以及 OpenAPI Schema 快照断言;
  • 运行单测:直接以仓库根目录为工作目录执行 pytest tests/test_tutorial/test_body/ -q
  • 本地起服务体验交互式文档:先确认 docs_src 可被 Python 导入(本仓库测试即以 docs_src.body.tutorial00X_py310 方式 importlib 加载模块),然后执行 uvicorn docs_src.body.tutorial001_py310:app --reload,访问 http://127.0.0.1:8000/docs 即可看到文中展示的自动生成文档,http://127.0.0.1:8000/openapi.json 可查看机器可读 Schema。

在此基础上,如果你需要为请求体字段附加更细的约束、在 body 中传递多个模型或嵌套结构,建议进一步阅读仓库中 Body - FieldsBody - Nested ModelsBody - Multiple Parameters 等后续章节。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
594
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
516
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388