在 FastAPI 中,查询参数(Query Parameters)的校验主要依赖于 Pydantic 和 FastAPI 提供的 Query 函数。FastAPI 会自动解析 URL 中的查询参数,并根据你提供的类型提示和校验规则进行验证。如果验证失败,会自动返回清晰的 HTTP 422 (Unprocessable Entity) 错误响应。
以下是 FastAPI 查询参数校验的全面指南,包含从基础到高级的用法。
1. 现代推荐写法:使用 Annotated (FastAPI 0.95.0+ / Pydantic V2)
官方目前最推荐使用 Python 的 Annotated,因为它能将类型提示和元数据(校验规则) 清晰地分离开来。
from fastapi import FastAPI, Query
from typing import Annotated
app = FastAPI()
@app.get("/items/")
async def read_items(
# 类型是 str | None,Query 提供校验规则,默认值为 None
q: Annotated[str | None, Query(min_length=3, max_length=50, description="搜索关键词")] = None,
skip: Annotated[int, Query(ge=0, le=100, description="跳过的记录数")] = 0,
):
return {"q": q, "skip": skip}2. 常用校验规则详解
2.1 必填与可选
- 可选:提供默认值(如
= None或= "default")。
PV - 必填:不提供默认值,或者使用
...(Ellipsis)。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 必填参数,且长度至少为 3
required_param: str = Query(..., min_length=3),
# 可选参数,默认值为 "hello"
optional_param: str = Query("hello", max_length=10)
):
return {"required": required_param, "optional": optional_param}2.2 数值范围校验
使用 ge (大于等于), gt (大于), le (小于等于), lt (小于)。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/users/")
async def read_users(
# age 必须大于等于 18 且小于等于 120
age: int = Query(ge=18, le=120, description="用户年龄"),
# score 必须大于 0 (不能等于 0)
score: float = Query(gt=0.0, description="用户分数")
):
return {"age": age, "score": score}2.3 字符串长度与正则表达式
min_length/max_length:限制字符串长度。pattern:使用正则表达式校验字符串格式(注意:Pydantic V2 中已弃用regex,请使用pattern)。
import re
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/validate-string/")
async def validate_string(
# 必须是 3-10 位字母数字
username: str = Query(..., min_length=3, max_length=10, pattern=r"^[a-zA-Z0-9]+$"),
# 必须是有效的邮箱格式 (简化版正则)
email: str = Query(..., pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")
):
return {"username": username, "email": email}2.4 枚举与固定值校验
如果你希望参数只能是几个特定的值,可以使用 Enum 或 Literal。
使用 Literal (推荐,更简洁):
from fastapi import FastAPI, Query
from typing import Literal
app = FastAPI()
@app.get("/models/")
async def get_model(
# 只能是 "resnet", "vgg" 或 "transformer"
model_name: Literal["resnet", "vgg", "transformer"] = Query(..., description="模型名称")
):
return {"model": model_name}使用 Enum:
from enum import Enum
from fastapi import FastAPI, Query
class ModelName(str, Enum):
resnet = "resnet"
vgg = "vgg"
transformer = "transformer"
app = FastAPI()
@app.get("/models-enum/")
async def get_model_enum(
model_name: ModelName = Query(..., description="模型名称")
):
return {"model": model_name.value}2.5 列表查询参数 (多个同名参数)
如果 URL 是 ?items=foo&items=bar,FastAPI 可以自动将其解析为列表。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/list/")
async def read_items_list(
# 接收多个 items 参数,至少需要 1 个,最多 5 个
items: list[str] = Query(..., min_length=1, max_length=5, description="物品列表")
):
return {"items": items}
# 请求示例: GET /items/list/?items=apple&items=banana
# 返回: {"items": ["apple", "banana"]}(注:如果希望用逗号分隔的单个参数如 ?items=apple,banana,可以声明类型为 str,然后在函数内部使用 .split(",") 处理,或者使用自定义校验器)
3. 进阶:自定义校验逻辑 (Annotated + 校验函数)
如果内置的 Query 参数无法满足需求(例如:校验两个参数之间的逻辑关系,或复杂的业务规则),可以结合 Pydantic 的 AfterValidator 或自定义函数。
from fastapi import FastAPI, Query
from typing import Annotated
from pydantic import AfterValidator
app = FastAPI()
# 1. 定义一个自定义校验函数
def validate_password(value: str) -> str:
if len(value) < 8:
raise ValueError("密码长度必须至少为 8 位")
if not any(char.isdigit() for char in value):
raise ValueError("密码必须包含至少一个数字")
return value
# 2. 创建带有自定义校验的类型别名
ValidPassword = Annotated[str, AfterValidator(validate_password)]
@app.get("/register/")
async def register(
# 使用自定义校验类型
password: ValidPassword = Query(..., description="用户密码"),
age: int = Query(..., ge=0)
):
# 自定义逻辑:年龄和密码长度的关联校验 (示例)
if age < 18 and len(password) < 12:
raise ValueError("未成年人密码长度必须至少为 12 位")
return {"message": "注册成功"}4. 校验失败时的默认响应
当校验失败时,FastAPI 会自动拦截并返回 422 Unprocessable Entity,响应体包含详细的错误信息,非常适合前端调试:
{
"detail": [
{
"type": "greater_than_equal",
"loc": ["query", "age"],
"msg": "Input should be greater than or equal to 18",
"input": "15",
"ctx": {
"ge": 18
}
}
]
}loc: 错误发生的位置(如["query", "age"]表示查询参数 age)。msg: 人类可读的错误信息。type: 错误类型(如string_too_short,greater_than_equal等)。
总结建议
- 优先使用
Annotated:代码更整洁,符合现代 Python 类型提示规范。 - 善用
description:在Query中添加描述,FastAPI 会自动将其生成到 Swagger UI (/docs) 中,极大提升 API 文档的可读性。 - Pydantic V2 注意:正则校验请使用
pattern而不是旧版的regex。 - 复杂逻辑用 Validator:简单的范围/长度用
Query,复杂的业务逻辑校验使用AfterValidator或在路由函数内部手动raise HTTPException。