在 FastAPI 中,请求体(Request Body) 是客户端发送给服务器的数据,通常用于 POST、PUT、PATCH 等请求,且默认格式为 JSON (application/json)。
FastAPI 处理请求体的核心武器是 Pydantic 模型。你只需定义数据的结构,FastAPI 就会自动完成:读取 JSON -> 类型转换 -> 数据验证 -> 生成 API 文档。
以下是处理请求体的核心用法和进阶技巧:
1. 基础用法:定义 Pydantic 模型
首先,导入 BaseModel 并定义你的数据结构。然后,在路径操作函数中将其作为参数类型。
from typing import Annotated
from pydantic import BaseModel
from fastapi import FastAPI
app = FastAPI()
# 1. 定义数据模型
class Item(BaseModel):
name: str
description: str | None = None # 可选字段
price: float
tax: float | None = None # 可选字段
# 2. 在路由中使用该模型作为请求体
@app.post("/items/")
async def create_item(item: Item):
# FastAPI 会自动验证传入的 JSON 是否符合 Item 模型
# 如果符合,item 就是一个 Item 实例
return {
"item_name": item.name,
"item_price": item.price,
"item_dict": item.model_dump() # Pydantic V2 转换为字典的方法
}如果客户端发送 {"name": "Laptop", "price": 999.99},FastAPI 会自动处理。如果发送 {"price": "not_a_number"},FastAPI 会返回清晰的 422 验证错误。
2. 字段级验证 (使用 Field)
如果你需要对请求体中的某个字段添加更严格的规则(如最小长度、数值范围、正则表达式),可以使用 pydantic.Field。
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(min_length=3, max_length=50, description="用户登录名")
age: int = Field(ge=18, le=120, description="年龄必须在 18 到 120 之间")
email: str = Field(pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$', description="必须是有效的邮箱")
@app.post("/users/")
async def create_user(user: User):
return {"message": "User created", "user": user.model_dump()}这些 description 还会自动同步到 Swagger UI (/docs) 中,极大提升 API 文档的质量。
3. 嵌套模型 (处理复杂 JSON)
Pydantic 模型可以作为其他模型的字段类型,完美支持嵌套的 JSON 结构。
from typing import List
from pydantic import BaseModel
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
price: float
images: List[Image] | None = None # 嵌套模型列表
@app.post("/items/complex/")
async def create_complex_item(item: Item):
return item客户端可以发送:{"name": "Phone", "price": 500, "images": [{"url": "http://...", "name": "front"}]}
4. 智能区分:路径参数 + 查询参数 + 请求体
FastAPI 最强大的特性之一是它能自动推断参数的来源。你可以在同一个函数中混合使用它们,FastAPI 绝不会混淆。
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.put("/items/{item_id}")
async def update_item(
item_id: Annotated[int, Path(description="The ID of the item to update")], # 1. 路径参数
q: Annotated[str | None, Query(description="Some query string")] = None, # 2. 查询参数 (?q=...)
item: Item, # 3. 请求体 (JSON)
):
results = {"item_id": item_id, "item": item}
if q:
results.update({"q": q})
return resultsFastAPI 的规则:
- 如果在路径中声明了(如
{item_id}),它就是路径参数。 - 如果是单一类型(
str,int,float,bool等),它默认是查询参数。 - 如果是 Pydantic 模型,它默认是请求体。
5. 多个请求体参数 (使用 Body)
默认情况下,FastAPI 期望请求体是一个单一的 JSON 对象,其键对应你的 Pydantic 模型。
如果你在一个函数中声明了多个 Pydantic 模型作为参数,FastAPI 会期望请求体是一个包含这些模型名称作为键的字典。
为了让客户端发送标准的 JSON(而不是嵌套字典),你可以使用 Body(embed=True) 强制将参数嵌入到请求体的顶层,或者(更推荐的做法)将它们合并到一个大的 Pydantic 模型中。
不推荐的做法(需要 embed=True):
from fastapi import Body
@app.post("/multi-body/")
async def multi_body(
item: Item,
user: User,
# 强制 FastAPI 期望 JSON 格式为: {"item": {...}, "user": {...}}
importance: Annotated[int, Body(embed=True, description="Priority level")]
):
return {"item": item, "user": user, "importance": importance}✅ 推荐做法(合并模型):
class CreateOrderRequest(BaseModel):
item: Item
user: User
importance: int = Field(description="Priority level")
@app.post("/orders/")
async def create_order(request: CreateOrderRequest):
return request.model_dump()将多个参数组合成一个 Request 模型,代码更清晰,且生成的 Swagger 文档更整洁。
6. 处理额外的未知字段
默认情况下,如果客户端在 JSON 中发送了 Pydantic 模型中未定义的字段,Pydantic 会直接忽略它们(在 V2 中这是默认行为,但明确声明是个好习惯)。
如果你想严格拒绝任何未定义的字段(提高安全性),可以配置模型:
from pydantic import BaseModel, ConfigDict
class StrictItem(BaseModel):
model_config = ConfigDict(extra="forbid") # 拒绝额外字段
name: str
price: float
@app.post("/strict-items/")
async def create_strict_item(item: StrictItem):
return item如果客户端发送 {"name": "A", "price": 10, "extra_field": "oops"},FastAPI 将返回 422 错误。
总结:请求体最佳实践
- 始终使用 Pydantic 模型:不要尝试手动解析
request.json(),让 Pydantic 为你做验证和类型转换。 - 使用
Annotated和Field:将验证规则(如min_length,gt)和文档描述(description)直接写在模型定义中。 - 复杂请求使用 Wrapper 模型:如果需要传递多个对象或额外元数据,创建一个包含所有字段的
XxxRequest模型,而不是在路由函数中堆砌多个参数。 - 利用
/docs测试:FastAPI 的 Swagger UI 会根据你的 Pydantic 模型自动生成完美的 JSON 请求体示例,直接在浏览器里点击 “Try it out” 即可测试。
接下来你想了解 FastAPI 的响应模型 (Response Model)(如何控制返回给客户端的数据),还是 异常处理 (Exception Handling)?