Skip to content

优化输入: 高级验证与元数据

在之前的章节中,我们依赖 str 和 int 等基本 Python 类型来验证数据。然而,实际应用程序需要更严格的规则。例如,用户名可能需要至少 3 个字符长,或者产品 ID 必须是一个正数。在本章中,我们将解锁 Query、Path 和 Body 的强大功能,以强制执行这些约束,并通过元数据(metadata)丰富我们的 API 文档。

FastAPI 允许您使用 Query 函数为参数声明额外的验证。为了使用它,我们将利用现代 Python 的 Annotated 语法。

想象一个搜索端点(endpoint),其中查询字符串 q 是可选的,但如果提供,则必须不少于 3 个字符且不超过 50 个字符。

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)] = None
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results

我们甚至可以使用 pattern 参数强制执行正则表达式。例如,确保字符串匹配特定格式,如固定大小的代码:

# 如果提供了 'q',确保它正好是 3 位数字
q: Annotated[str | None, Query(pattern="^\\d{3}$")] = None

正如 Query 处理查询参数一样,Path 处理路径参数。由于路径参数总是必需的(它们是 URL 路由的一部分),我们经常使用 Path 来验证数值范围。

常见的验证器包括:

  • gt:大于
  • ge:大于或等于
  • lt:小于
  • le:小于或等于
from fastapi import Path
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item", ge=1)],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
return {"item_id": item_id, "q": q}

在此示例中,如果用户尝试访问 /items/0 或 /items/-5,FastAPI 将自动拒绝该请求并返回验证错误,因为 item_id 必须大于或等于 1。

有时您希望在请求体中传递单个值(例如一个简单的字符串),而不是由 Pydantic 模型定义的完整 JSON 对象。默认情况下,FastAPI 假定简单类型是查询参数。为了指示 FastAPI 从 JSON 请求体中读取它们,我们使用 Body。

from fastapi import Body
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Item, # 一个 Pydantic 模型
importance: Annotated[int, Body()] # 来自请求体的单个值
):
return {"item_id": item_id, "item": item, "importance": importance}

FastAPI 将期望一个如下所示的 JSON 请求体:

{
"item": {
"name": "Foo",
"price": 45.2
},
"importance": 5
}

FastAPI 最好的特性之一就是自动文档。使用 Query、Path 和 Body,您可以添加直接显示在 Swagger UI 和 ReDoc 中的元数据。

  • title:参数的简明标题。
  • description:参数功能的详细说明。支持 Markdown!
  • alias:如果 URL 中的参数名称需要与您的 Python 变量不同(例如 item-query 与 item_query),此项很有用。
  • deprecated:设置为 True 可在文档中将参数标记为已弃用,同时不破坏 API。
q: Annotated[
str | None,
Query(
title="Query String",
description="Query string for the items to search in the database that have a good match",
min_length=3,
deprecated=True
)
] = None

通过添加这些详细信息,您可以将代码转化为自文档化的规范,从而让前端开发者和 API 调用者(consumers)的生活更轻松。