这篇文章介绍 FastAPI 中的参数验证功能

Query Parameters and String Validations

FastAPI 允许为参数声明额外的信息和验证规则

PYTHON
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
async def read_items(q: str | None = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
Click to expand and view more

q 是类型为 str | None 的查询参数, 这意味着它可以是字符串, 也可以是 None. 其默认值是 None, 因此 FastAPI 会识别它为“可选参数”

FastAPI 通过 = None 的默认值知道该参数是非必填的

使用 str | None 还能帮助编辑器提供更好的类型提示和错误检测

Additional validation 额外验证

即使 q 是可选的, 但仍然可以设置条件: 如果提供了 q, 则长度不能超过50个字符

使用 QueryAnnotated 来实现

PYTHON
from typing import Annotated
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(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
Click to expand and view more

使用 Annotated 包装后, 就可以传递额外的元数据(Query(max_length=5)), 用于校验或者文档

注意: 使用 Annotated 的时候,不能在 Query() 中再次使用 default

使用 Annotated 有以下优点

More Validations 更多验证

Declare more metadata 添加更多元信息

这些信息会出现在 OpenAPI 文档中

PYTHON
q: Annotated[str | None, Query(
    title="查询字符串",
    description="用于数据库中模糊搜索匹配的查询字符串",
    min_length=3
)] = None
Click to expand and view more

Alias parameters 参数别名

有时想使用一个在 Python 中非法的别名, 例如 item-query

PLAINTEXT
http://127.0.0.1:8000/items/?item-query=foobaritems
Click to expand and view more

最接近的变量名为 item_query, 但是 item-query 不能为变量名

此时, 可以使用别名 alias

PYTHON
q: Annotated[str | None, Query(alias="item-query")] = None
Click to expand and view more

Deprecating parameters 弃用参数

想标记某个参数已被弃用, 可以加上

PYTHON
Query(..., deprecated=True)
Click to expand and view more

Exclude parameters from OpenAPI 从OpenAPI中隐藏参数

可以设置参数不出现在自动生成的文章中

PYTHON
hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None
Click to expand and view more

Custom validation 自定义校验

若内建参数不够用, 可以使用 Pydantic v2 的 AfterValidator

PYTHON
from fastapi import FastAPI
from pydantic import AfterValidator
from typing import Annotated

def check_valid_id(id: str):
    if not id.startswith(("isbn-", "imdb-")):
        raise ValueError("Invalid ID format, 必须以 'isbn-' 或 'imdb-' 开头")
    return id

@app.get("/items/")
async def read_items(
    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,
):
    if id:
        team = data.get(id)
    else:
        id, item = random.choice(list(data.items()))
    return {"id": id, "name": item}
Click to expand and view more

Path Parameters and Numberic Validations

和使用 Query 查询参数声明更多验证规则和元数据一样, 也可以使用 Path 为路径参数声明相同类型的规则验证和元数据

Import Path 导入路径

首先, 从 fastapi 中导入 Path, 并导入 Annotated

PYTHON
from typing import Annotated
from fastapi import FastAPI, Path, Query

app = FastAPI()

@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="要获取的物品 ID")],
    q: Annotated[str | None, Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
Click to expand and view more

Declare metadata 声明元数据

可以像在 Query 中一样声明所有的参数

PYTHON
item_id: Annotated[int, Path(title="要获取的物品 ID")]
Click to expand and view more

⚠️ 路径参数总是必填的, 它必须作为路径的一部分存在. 即使将它设为 None 或指定默认值, 也不会生效, 它仍然是必须的

Order the parameters 自由排序参数

如果希望 query parameter 声明为必填的 str, 并且不需要声明任何其他事情, 那么不需要用 Query() 包裹

但是对于 path parameter item_id 仍然需要使用 Path, 并且出于一些原因并不像使用 Annotated

如果将有 defalult 默认值的参数, 放到没有默认值参数前面, 那么 Python 会报错, 所以要这样声明函数

PYTHON
from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="要获取的物品 ID")):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
Click to expand and view more

但是, 如果使用 Annotated 就不会有这个顺序的问题, 因为默认值并不写在函数参数中

PYTHON
@app.get("/items/{item_id}")
async def read_items(
    q: str, item_id: Annotated[int, Path(title="要获取的物品 ID")]
):
    ...
Click to expand and view more

Order the parameters tricks 参数顺序技巧

如果不想使用 Annotated, 但是又想:

那可以使用一个小技巧: 在函数参数前面加一个星号 *

作用是: 告诉 Python, 后面所有参数必须作为关键字参数传入 (即使用key=value的方法, 不能省略参数名)

PYTHON
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
    ...
Click to expand and view more

Better with Annotated 推荐使用Annotated

如果使用 Annotated, 由于不是用参数默认值来传递 Path()Query(), 就不需要使用*这种语法

PYTHON
# Python 3.9+
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
    ...
Click to expand and view more

Number Validations 数字验证

在 FastAPI 中, 可以通过 Path()Query() (以及其他参数类) 为数值类型参数添加约数条件, 有以下四种:

这些验证适用于路径参数(path parameter)和查询参数(query parameter), 并且支持 int 和 float 类型

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut