Skip to content

06. FastAPI 请求参数类型验证 ​

从“收到文本”走向“收到可靠的数据” ​

类型验证解决三个问题:参数从哪里取、能否转成目标类型、是否满足约束。例如 /items/12?enabled=true 中,12 可转成整数,true 可转成布尔值。验证后业务代码不必反复写转换逻辑。

FastAPI 根据路径模板、类型和声明方式判断来源:出现在 {} 中的是路径参数;普通标量一般来自查询串;Pydantic 模型一般来自请求体。Query、Path、Body 可显式标注来源。

同时验证路径、查询与正文 ​

python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class ItemIn(BaseModel):
    name: str
    price: float
    note: str | None = None

@app.post("/shops/{shop_id}/items")
def create_item(shop_id: int, item: ItemIn, enabled: bool = True):
    return {"shop_id": shop_id, "enabled": enabled,
            "item": item.model_dump()}

保存为 main.py,启动 uv run uvicorn main:app --reload,在 /docs 调用:路径填 12,查询填 false,正文填 {"name":"键盘","price":199}。响应中的 shop_id 是数字、enabled 是布尔值。

再将路径改成 abc,或把价格改成 "便宜",应得到 422。错误正文的 detail 是一个列表,loc 指出位置,例如 body → price,msg 描述原因。客户端应关注稳定的字段路径与错误分类,不应依赖某一版本的整段英文提示。

必填、可空、默认值是三件事 ​

声明能否不传能否传 null
name: str否否
name: str = "匿名"是否
`name: strNone`否
`name: strNone = None`是

以上以 Pydantic 2 模型字段为例。None 表示值可为空;有没有默认值决定字段能否省略。

转换模式与严格模式 ​

默认验证允许部分合理转换,例如把 "12" 转成整数,但不是任意值都能转换。若 JSON 正文中的整数必须真正是数字,可声明 Field(strict=True)。不要把严格整数规则直接照搬到查询串:查询串天然是文本,严格设置可能拒绝原本可接受的请求。

日期用 date,时间用带明确时区约定的 datetime,唯一标识可用 UUID,固定选项可用 Enum 或 Literal。金额通常使用 Decimal 配合精度约束,避免浮点累加误差。

验证不等于业务检查 ​

“价格必须大于零”适合字段约束;“库存足不足”“用户名是否已存在”“当前用户能否修改订单”需要查询数据库或权限系统,通常放业务层。422 处理结构错误,404 处理资源不存在,409 可处理唯一性冲突。

练习:为商品增加必填的 stock: int,分别测试缺字段、字符串数字和完全不能转换的文本;再为备注增加可空默认值,解释两者区别。