FastAPI 进阶教程:参数传递与响应校验
上一节我们实现了基础的 HelloWorld API,这一节将聚焦实际开发核心需求 ------ 参数传递(路径 / 查询 / 请求体)与响应数据校验,结合 Pydantic 模型让接口更规范、更健壮。
一、核心依赖与前置说明
- 依赖工具:Pydantic(FastAPI 内置,用于数据校验和模型定义)。
- 核心目标:通过类型注解定义参数 / 响应格式,FastAPI 自动完成校验、转换和文档生成。
- 适用场景:接口需要接收用户输入(如查询条件、表单数据)或返回结构化结果时。
二、参数传递的 3 种核心方式
2.1 路径参数(Path Parameters)
用于标识资源的唯一标识(如用户 ID、商品编号),直接嵌入 URL 路径中。
基础用法(无校验)
python
from fastapi import FastAPI
app = FastAPI()
# 路径参数 item_id 嵌入 URL,类型注解为 int
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id, "message": "获取商品成功"}
- 访问示例:http://127.0.0.1:8000/items/10,返回 {"item_id":10,"message":"获取商品成功"}。
- 自动转换:若访问 items/abc,FastAPI 会返回 422 错误(类型不匹配),无需手动处理。
进阶用法(路径参数校验)
通过 Path 类添加校验规则(如数值范围、描述):
python
from fastapi import FastAPI, Path
from typing import Optional
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
# ge=1:大于等于 1,le=100:小于等于 100,description 用于接口文档
item_id: int = Path(..., ge=1, le=100, description="商品 ID,范围 1-100"),
q: Optional[str] = None # 可选查询参数,下文详解
):
return {"item_id": item_id, "q": q}
- 访问示例:/items/50?q=手机 正常响应,/items/101 会返回 422 校验错误。
2.2 查询参数(Query Parameters)
用于过滤、分页等非核心参数(如搜索关键词、页码),以 ?key=value 形式附加在 URL 后。
基础用法(可选参数 + 默认值)
python
@app.get("/users/")
async def get_users(
page: int = 1, # 必选查询参数,默认值 1(不传递时使用默认值)
limit: int = 10, # 每页条数,默认 10
keyword: Optional[str] = None # 可选查询参数,默认 None
):
# 模拟分页查询逻辑
return {
"page": page,
"limit": limit,
"keyword": keyword,
"data": [{"user_id": 1, "name": "张三"}, {"user_id": 2, "name": "李四"}]
}
- 访问示例:/users/?page=2&limit=20&keyword=张,返回对应分页和筛选结果。
- 校验特性:若传递 page=abc,会自动返回类型错误。
进阶用法(查询参数校验)
通过 Query 类添加校验规则(如字符串长度、正则匹配):
python
from fastapi import FastAPI, Query
@app.get("/users/")
async def get_users(
page: int = Query(1, ge=1, description="页码,最小 1"),
limit: int = Query(10, ge=5, le=50, description="每页条数,5-50 条"),
# min_length=2:最小长度 2,max_length=10:最大长度 10
keyword: Optional[str] = Query(None, min_length=2, max_length=10)
):
return {"page": page, "limit": limit, "keyword": keyword, "data": []}
2.3 请求体(Request Body)
用于传递复杂数据(如创建用户、提交表单),以 JSON 格式发送(FastAPI 自动解析)。
需通过 Pydantic 模型定义请求体结构。
步骤 1:定义 Pydantic 模型
python
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# 定义请求体模型,继承 BaseModel
class UserCreate(BaseModel):
name: str # 必选字段,字符串类型
age: int = Field(..., ge=0, le=120, description="年龄,0-120 岁") # 带校验的必选字段
email: str = Field(..., pattern=r"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+.[a-zA-Z0-9_-]+$") # 邮箱正则校验
address: Optional[str] = None # 可选字段,默认 None
# 定义响应体模型(可选,用于规范返回格式)
class UserResponse(BaseModel):
id: int
name: str
age: int
email: str
address: Optional[str] = None
class Config:
orm_mode = True # 支持从 ORM 对象(如 SQLAlchemy 模型)转换为 JSON
步骤 2:使用模型接收请求体
python
@app.post("/users/", response_model=UserResponse) # 指定响应模型,自动校验返回数据
async def create_user(user: UserCreate): # user 参数自动解析 JSON 请求体
# 模拟数据库插入,生成用户 ID
user_id = 1001
# 返回数据会被 UserResponse 校验,确保格式一致
return {
"id": user_id,
"name": user.name,
"age": user.age,
"email": user.email,
"address": user.address
}
测试请求体
- 发送 POST 请求到 http://127.0.0.1:8000/users/,请求体 JSON:
perl
{
"name": "王五",
"age": 25,
"email": "wangwu@example.com",
"address": "北京市海淀区"
}
- 响应结果:自动校验请求体(如 email 格式错误会返回 422),返回数据严格遵循 UserResponse 结构。
三、响应校验的核心作用
- 确保返回数据格式统一,避免前端对接混乱。
- 自动过滤多余字段(如请求体中的额外参数不会被返回)。
- 文档自动同步:/docs 页面会显示请求体和响应体的结构化示例。
四、实战:组合参数示例(路径 + 查询 + 请求体)
python
@app.put("/items/{item_id}", response_model=UserResponse)
async def update_item(
item_id: int = Path(..., ge=1, description="商品 ID"),
is_active: bool = Query(True, description="是否启用商品"),
user: UserCreate # 请求体
):
return {
"id": item_id,
"name": user.name,
"age": user.age,
"email": user.email,
"address": user.address
}
- 访问示例:PUT 请求 http://127.0.0.1:8000/items/5?is_active=true,携带上述 JSON 请求体。
- 校验逻辑:路径参数、查询参数、请求体分别按规则校验,任意环节出错返回 422 错误。
五、常见错误与排查
- 422 错误:数据校验失败(如类型不匹配、数值超出范围、正则不匹配),查看响应体的 detail 字段可获取具体原因。
- 请求体无法解析:未定义 Pydantic 模型,或请求头 Content-Type 不是 application/json。
- 可选字段必填:未给 Optional 字段设置默认值(如 keyword: Optional[str] 需改为 keyword: Optional[str] = None)。