FastAPI 的核心功能之一:请求体(Request Body)

请求体主要用于 POST、PUT、PATCH 等 HTTP 方法中,用来接收客户端发送的 JSON 数据(比如创建用户、提交表单、上传配置等)。

🧩 一、什么是请求体(Request Body)?

  • 请求体是 HTTP 请求中 Content-Type: application/json 的数据部分。
  • 例如,前端发送:

    POST /users/
    {
      "name": "Alice",
      "age": 30,
      "email": "alice@example.com"
    }

    这个 JSON 就是 请求体

✅ 在 FastAPI 中,请求体通过 Pydantic 模型(BaseModel) 定义和校验。

✅ 二、基本用法:定义模型 + 接收请求体

🔹 步骤 1:导入并定义 Pydantic 模型

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class UserCreate(BaseModel):
    name: str
    age: int
    email: str
💡 BaseModel 是 Pydantic 提供的基类,用于定义数据结构。

🔹 步骤 2:在路由函数中使用模型作为参数

@app.post("/users/")
def create_user(user: UserCreate):
    return {
        "message": f"User {user.name} created!",
        "user": user
    }
  • FastAPI 会自动:

    • 解析 JSON 请求体
    • 校验字段类型(name 必须是字符串,age 必须是整数)
    • 转换为 UserCreate 对象
    • 如果校验失败 → 自动返回 422 错误

🔹 测试示例

请求:

POST /users/
Content-Type: application/json

{
  "name": "Bob",
  "age": 25,
  "email": "bob@example.com"
}

响应:

{
  "message": "User Bob created!",
  "user": {
    "name": "Bob",
    "age": 25,
    "email": "bob@example.com"
  }
}

错误请求(缺少字段):

{ "name": "Bob" }  // 缺少 age 和 email

→ 自动返回 422,详细说明缺失字段!


⚠️ 三、重要注意事项(新手必看)

1️⃣ 请求体只能有一个(主参数)

FastAPI 规定:一个路由中只能有一个请求体参数(即一个 Pydantic 模型)。

# ❌ 错误:两个请求体?
@app.post("/items/")
def create_item(item: Item, user: User):  # 不行!

✅ 正确做法:把多个数据合并到一个模型中,或使用 混合参数(见下文)。


2️⃣ 请求体参数不能有默认值(除非嵌套)

# ❌ 这样写会被 FastAPI 当作查询参数!
def create_user(user: UserCreate = None):

✅ 请求体参数不要设默认值,它本身就是可选/必需由模型字段决定。


3️⃣ 字段默认值 & 可选字段

在模型中控制字段是否必需:

from typing import Optional

class UserCreate(BaseModel):
    name: str                  # 必需
    age: int = 18              # 可选,默认 18
    email: Optional[str] = None  # 可选,可为 None
  • 请求 { "name": "Alice" } → 合法
  • user.age 会自动设为 18
💡 Python 3.10+ 可用 str | None 代替 Optional[str]

🛠 四、高级用法

🔸 1. 嵌套模型(Nested Models)

class Address(BaseModel):
    city: str
    country: str

class UserCreate(BaseModel):
    name: str
    address: Address  # 嵌套

@app.post("/users/")
def create_user(user: UserCreate):
    return user

请求体:

{
  "name": "Alice",
  "address": {
    "city": "Beijing",
    "country": "China"
  }
}

🔸 2. 混合使用:路径参数 + 查询参数 + 请求体

这是最常见场景!

@app.put("/users/{user_id}")
def update_user(
    user_id: int,               # ← 路径参数
    active: bool = True,        # ← 查询参数(?active=false)
    user: UserCreate            # ← 请求体(JSON)
):
    return {
        "user_id": user_id,
        "active": active,
        "updated_data": user
    }

请求:

PUT /users/123?active=false
Content-Type: application/json

{
  "name": "Alice Updated",
  "age": 31,
  "email": "alice.new@example.com"
}

✅ FastAPI 能完美区分三者!


🔸 3. 使用 Field 添加校验和文档

类似 Query,可用 Field 控制模型字段:

from pydantic import BaseModel, Field

class UserCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    age: int = Field(ge=0, le=120)  # 0 ≤ age ≤ 120
    email: str

# ... 路由不变
  • ... 表示该字段必需
  • 自动校验 + 生成 OpenAPI 文档说明

📊 五、请求体 vs 查询参数 vs 路径参数 —— 一句话总结

类型用途HTTP 方法是否必需示例
路径参数标识资源GET/PUT/DELETE✅ 是/users/123
查询参数过滤/分页/选项通常 GET❌ 否?page=2&limit=10
请求体提交复杂数据POST/PUT/PATCH✅ 由模型决定JSON 数据

✅ 六、最佳实践建议

  1. 始终用 Pydantic 模型定义请求体 → 自动校验 + 文档 + 类型安全
  2. 不要混用多个请求体 → 合并到一个模型中
  3. 敏感字段(如密码)记得加校验

    password: str = Field(..., min_length=8)
  4. 使用嵌套模型表达复杂结构(如订单含商品列表)
  5. 利用 FastAPI 自动生成的交互式文档(访问 /docs 测试!)

🎯 小练习

写一个 API 用于创建商品:

  • 路径:POST /products/
  • 请求体包含:

    • name: str
    • price: float(必须 > 0)
    • tags: list[str](可选,默认空列表)
  • 返回创建的商品信息
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List

app = FastAPI()

class ProductCreate(BaseModel):
    name: str
    price: float = Field(gt=0)  # greater than 0
    tags: List[str] = []

@app.post("/products/")
def create_product(product: ProductCreate):
    return {
        "id": 1001,  # 模拟 ID
        "product": product
    }