FastAPI 查询参数校验
FastAPI 允许你为查询参数声明额外的校验规则和元数据,例如字符串长度限制、正则匹配等。通过 Query 和 Annotated,你可以在不改变函数逻辑的情况下增强参数校验。
基本校验
以下示例为查询参数 q 添加最大长度限制:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 使用 Annotated + Query 添加校验
q: Annotated[str | None, Query(max_length=50)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 使用 Annotated + Query 添加校验
q: Annotated[str | None, Query(max_length=50)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
代码说明:
| 部分 | 说明 |
|---|---|
Annotated[str | None, ...] | 类型注解,表示 q 可以是字符串或 None |
Query(max_length=50) | 校验规则,q 的最大长度为 50 个字符 |
= None | 默认值,使参数变为可选 |
FastAPI 推荐使用
Annotated方式声明校验,而非将Query作为默认值。因为Annotated方式下,函数的默认值就是真正的默认值,更符合 Python 的直觉,且编辑器和类型检查工具支持更好。
添加更多校验
你可以同时添加多种校验规则:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 同时限制最小长度、最大长度和正则表达式
q: Annotated[str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$")] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 同时限制最小长度、最大长度和正则表达式
q: Annotated[str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$")] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
字符串校验参数:
| 参数 | 类型 | 说明 |
|---|---|---|
min_length | int | 最小长度 |
max_length | int | 最大长度 |
pattern | str | 正则表达式匹配 |
正则表达式 ^fixedquery$ 的含义:
^-- 必须以接下来的字符开头fixedquery-- 值必须精确等于fixedquery$-- 到此结束,后面不能有其他字符
带默认值的校验
你可以为查询参数同时设置默认值和校验规则:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 默认值为 "fixedquery",同时要求最小长度为 3
q: Annotated[str, Query(min_length=3)] = "fixedquery",
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 默认值为 "fixedquery",同时要求最小长度为 3
q: Annotated[str, Query(min_length=3)] = "fixedquery",
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
任何类型的默认值(包括非
None值)都会让参数变为可选。没有默认值也没有Query(default=...)的参数是必填的。
必填参数
使用 Query 时,如果不声明默认值,参数就是必填的:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 没有 = None,所以 q 是必填参数
q: Annotated[str, Query(min_length=3)],
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 没有 = None,所以 q 是必填参数
q: Annotated[str, Query(min_length=3)],
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
results.update({"q": q})
return results
必填但可以为 None
有时你需要客户端必须传值,但值可以是 None:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 客户端必须提供 q 参数,但值可以是 None
q: Annotated[str | None, Query(min_length=3)],
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# 客户端必须提供 q 参数,但值可以是 None
q: Annotated[str | None, Query(min_length=3)],
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
查询参数列表 / 多个值
使用 Query 可以声明接收多个值的查询参数:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# q 可以在 URL 中出现多次,值会被收集为列表
q: Annotated[list[str] | None, Query()] = None,
):
query_items = {"q": q}
return query_items
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# q 可以在 URL 中出现多次,值会被收集为列表
q: Annotated[list[str] | None, Query()] = None,
):
query_items = {"q": q}
return query_items
访问 http://127.0.0.1:8000/items/?q=foo&q=bar,返回:
{"q": ["foo", "bar"]}
要声明类型为
list的查询参数,必须显式使用Query(),否则 FastAPI 会将其解释为请求体。
声明元数据
Query 还支持为参数添加元数据,这些信息会出现在 API 文档中:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Annotated[str | None, Query(
title="查询字符串", # 参数标题
description="用于筛选商品的查询字符串", # 参数描述
min_length=3,
max_length=50,
alias="item-query", # URL 中的参数名别名
deprecated=True, # 标记为已弃用
)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Annotated[str | None, Query(
title="查询字符串", # 参数标题
description="用于筛选商品的查询字符串", # 参数描述
min_length=3,
max_length=50,
alias="item-query", # URL 中的参数名别名
deprecated=True, # 标记为已弃用
)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
元数据参数说明:
| 参数 | 说明 | 使用场景 |
|---|---|---|
alias | URL 中的参数名别名 | 参数名含连字符(如 item-query),不是有效 Python 变量名时 |
title | 参数标题 | 在文档中显示参数标题 |
description | 参数描述 | 在文档中显示参数的详细说明 |
deprecated | 标记为已弃用 | 参数仍可使用,但文档中会标记为"已弃用" |
include_in_schema | 是否出现在 API 文档中 | 设为 False 可隐藏参数 |
从 OpenAPI 中排除参数
如果某个查询参数不应出现在 API 文档中:
实例
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# hidden_query 不会出现在 API 文档中,但仍然可以使用
hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None,
):
if hidden_query:
return {"hidden_query": hidden_query}
return {"items": [{"item_id": "Foo"}]}
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
# hidden_query 不会出现在 API 文档中,但仍然可以使用
hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None,
):
if hidden_query:
return {"hidden_query": hidden_query}
return {"items": [{"item_id": "Foo"}]}
小结
查询参数校验的核心要点:
- 使用
Annotated+Query声明校验规则(推荐方式) - 字符串校验:
min_length、max_length、pattern - 没有默认值 = 必填参数,有默认值 = 可选参数
alias用于 URL 中使用非 Python 变量名的参数名deprecated=True标记过时的参数- 使用
list[str]接收多个相同名称的查询参数
