696 字
3 分钟
参数校验
2025-01-05

查询参数和字符串校验#

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

查询参数 q 的类型为 str,默认为 None,因此他是可选的

额外的检验#

即使 Q 是可选的,但只要提供了该参数,该参数的长度要<50

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

这里我们使用了 Query 来替代 None,并且设置他的最大长度为 50

当使用 Query 当你使用 Query 显式地定义查询参数时,你还可以声明它去接收一组值,或换句话来说,接收多个值。

例如,要声明一个可在 URL 中出现多次的查询参数 q,你可以这样写:

from typing import List, Union

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

我们可以在 query 中添加更多的元数据用于描述我们的代码

@app.get("/items/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        deprecated=True,#表示将要弃用
    ),
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

路径参数和数值校验#

与 query 相似,我们也可是使用 Path 为路径参数声明校验和元数据

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="The ID of the item to get")],
    q: Annotated[str | None, Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

这里的 Annotated 就是加点辅助信息

路径参数是必须得,即使被申明为=None!,所以路径参数应该放在 query 的前面 (如果你将带有「默认值」的参数放在没有「默认值」的参数之前,Python 将会报错。)

数值校验#

@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=1,le=1000)], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

查询参数#

可以使用 pydantic 模型来声明它们

class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []

@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    return filter_query

与在路径操作函数中使用 Query、Path 、Body 声明校验与元数据的方式一样,可以使用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。

请求体#

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

class User(BaseModel):
    username: str
    full_name: str | None = None

@app.put("/items/{item_id}")
async def update_item(
    item_id: int, item: Item, user: User, importance: Annotated[int, Body(gt=0)]
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results

这里的 importance 是一个单一值,请求体应该如下:

{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}