FastAPI 教程

FastAPI 查询参数

在 FastAPI 中,查询参数(Query Parameters) 是 URL 中 ? 后面的键值对,多个参数之间用 & 分隔(例如:/items?skip=0&limit=10)。

FastAPI 的核心魔法在于:任何未在路径(Path)中声明的函数参数,都会被自动视为查询参数

以下是 FastAPI 查询参数的核心用法和进阶技巧:


1. 基本用法

直接在函数签名中声明参数即可。FastAPI 会自动从 URL 的查询字符串中提取并转换类型。

纯文本
plaintext
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}
  • 访问 /items/:返回 {"skip": 0, "limit": 10}
  • 访问 /items/?skip=20&limit=5:返回 {"skip": 20, "limit": 5}
  • 访问 /items/?skip=foo:返回 422 错误,因为 foo 无法转换为 int

2. 可选查询参数 (Optional)

如果你希望某个查询参数是可选的,只需为其提供一个默认值(通常是 None 或某个具体值)。

纯文本
plaintext
from typing import Optional # Python 3.10+ 可直接用 str | None

@app.get("/items/")
async def read_items(q: str | None = None):
    if q:
        return {"items": [{"name": "Item Foo"}, {"name": "Item Bar"}], "q": q}
    return {"items": [{"name": "Item Foo"}, {"name": "Item Bar"}]}
  • 访问 /items/qNone
  • 访问 /items/?q=somequeryq"somequery"

3. 使用 Query 添加高级验证

你可以从 fastapi 导入 Query,为查询参数添加更严格的验证规则(如长度限制、正则表达式、是否废弃等)。

纯文本
plaintext
from fastapi import FastAPI, Query

app = FastAPI()

# 传统写法
@app.get("/items/")
async def read_items(
    q: str | None = Query(
        default=None, 
        title="Search query",
        description="Query string to search for items",
        min_length=3,
        max_length=50,
        regex="^fixedquery$" # 只允许精确匹配 "fixedquery"
    )
):
    return {"q": q}

如果传入的 q 长度小于 3 或不符合正则,FastAPI 会自动返回清晰的 422 验证错误。


4. 现代推荐写法:使用 Annotated (Python 3.9+)

FastAPI 官方强烈推荐使用 typing.Annotated。它将类型和元数据(如 Query)分离,使代码更清晰,且对类型检查器(如 mypy)更友好。

纯文本
plaintext
from typing import Annotated
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    # 类型提示在前,Query 验证规则在后,默认值放在最后
    q: Annotated[str | None, Query(min_length=3, max_length=50, description="Search query")] = None
):
    return {"q": q}

5. 声明“必需”的查询参数

如果某个查询参数是必须提供的(没有默认值),你可以使用 ... (Ellipsis) 作为默认值,或者在 Annotated 中不提供默认值。

纯文本
plaintext
from fastapi import Query

# 传统写法:使用 ... 表示必需
@app.get("/items/")
async def read_items(q: str = Query(..., min_length=3)):
    return {"q": q}

# 现代 Annotated 写法:直接不给默认值
@app.get("/items/")
async def read_items_modern(
    q: Annotated[str, Query(min_length=3)]
):
    return {"q": q}

此时访问 /items/(不带 ?q=...)将直接返回 422 错误,提示该字段缺失 (field required)。


6. 多个同名查询参数 (List)

如果 URL 中包含多个同名的查询参数(例如 ?q=apple&q=banana),你可以将类型声明为 list,FastAPI 会自动将其解析为列表。

纯文本
plaintext
from typing import Annotated
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(
    # 允许传递多个 q 参数,例如 ?q=apple&q=banana
    q: Annotated[list[str] | None, Query(title="Query string")] = None
):
    return {"q": q}
  • 访问 /items/?q=apple&q=banana:返回 {"q": ["apple", "banana"]}
  • 访问 /items/:返回 {"q": None}

7. 布尔值转换 (Boolean Conversion)

FastAPI 对布尔查询参数有特殊的智能解析。它不仅识别 true/false,还能识别 1/0on/offyes/no 等。

纯文本
plaintext
@app.get("/items/")
async def read_items(short: bool = False):
    if short:
        return {"message": "Short response"}
    return {"message": "Full response with lots of details"}
  • 访问 /items/?short=1/items/?short=true/items/?short=yesshort 都会被解析为 True
  • 访问 /items/?short=0 或不传:shortFalse

8. 标记参数为“已废弃” (Deprecated)

如果你的 API 正在迭代,某个查询参数即将被移除,可以使用 deprecated=True。这会在自动生成的 Swagger UI (OpenAPI) 文档中将该参数划掉并标记为废弃,但代码仍会正常处理它。

纯文本
plaintext
@app.get("/items/")
async def read_items(
    q: Annotated[str | None, Query(deprecated=True)] = None
):
    return {"q": q}

💡 最佳实践总结

  1. 优先使用 Annotated:这是现代 FastAPI 开发的标准,代码可读性和类型提示支持最好。
  2. 提供合理的默认值:除非业务逻辑强制要求,否则尽量为查询参数提供默认值(如分页的 skip=0, limit=10),以提高 API 的易用性。
  3. 善用 Querydescription:填写清晰的描述,FastAPI 会自动将其渲染到 Swagger UI 中,极大降低前端/其他开发者的对接成本。
  4. 注意类型安全:始终声明类型(如 int, str, bool),让 FastAPI 帮你挡掉非法的输入,而不是在业务逻辑里手动做 try...except

如果你需要了解如何处理更复杂的场景(如依赖注入中的查询参数、自定义解析逻辑等),随时告诉我!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注