路径参数和查询参数

FastAPI 会根据函数参数的位置和名字,自动判断参数来自哪里。

一、路径参数

路径参数写在 URL 路径里,用 {} 包起来。

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

访问:

GET /users/1

返回:

{
    "user_id": 1
}

这里的 user_id: int 会让 FastAPI 自动做类型转换。

如果访问:

GET /users/abc

FastAPI 会返回 422 Unprocessable Entity,因为 "abc" 不能转成整数。

二、路径顺序很重要

如果同时有固定路径和动态路径,固定路径要写在前面。

@app.get("/users/me")
def get_current_user():
    return {"user_id": "current user"}


@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

这样访问 /users/me 才会进入 get_current_user()

如果把 /users/{user_id} 写在前面,me 会被当成 user_id 解析,然后因为不能转成 int 报错。

三、查询参数

查询参数写在 URL 的问号后面:

/items/?skip=0&limit=10

在 FastAPI 里,只要函数参数没有出现在路径中,它默认就是查询参数。

@app.get("/items/")
def list_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

访问:

GET /items/?skip=20&limit=10

返回:

{
    "skip": 20,
    "limit": 10
}

默认值的含义:

写法含义
skip: int = 0可选参数,不传时使用 0
limit: int = 10可选参数,不传时使用 10
keyword: str必填参数,不传会报 422

四、可选查询参数

@app.get("/items/")
def list_items(keyword: str | None = None):
    return {"keyword": keyword}

含义:

  • str | None:这个值可以是字符串,也可以是 None
  • = None:不传时默认值是 None

Pydantic v2 里,str | None 不等于可选参数。只有写了默认值,例如 str | None = None,才表示可以不传。

五、布尔查询参数

@app.get("/items/")
def list_items(short: bool = False):
    return {"short": short}

这些值通常都会被解析成 True

?short=true
?short=1
?short=yes
?short=on

这些值通常会被解析成 False

?short=false
?short=0
?short=no
?short=off

六、使用 Query 添加校验

FastAPI 当前推荐配合 Annotated 写参数元数据。

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
def list_items(
    page: Annotated[int, Query(ge=1, description="页码,从 1 开始")] = 1,
    page_size: Annotated[int, Query(ge=1, le=100, description="每页数量")] = 10,
    keyword: Annotated[str | None, Query(max_length=50, description="搜索关键词")] = None,
):
    return {
        "page": page,
        "page_size": page_size,
        "keyword": keyword,
    }

常用校验参数:

参数含义示例
ge大于等于Query(ge=1)
gt大于Query(gt=0)
le小于等于Query(le=100)
lt小于Query(lt=100)
min_length最小长度Query(min_length=2)
max_length最大长度Query(max_length=50)
pattern正则表达式Query(pattern=r"^1[3-9]\d{9}$")
description文档描述Query(description="关键词")

七、路径参数也能校验

路径参数用 Path

from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/users/{user_id}")
def get_user(
    user_id: Annotated[int, Path(ge=1, description="用户 ID,必须大于等于 1")]
):
    return {"user_id": user_id}

访问 /users/0 会返回 422,因为 user_id 不满足 ge=1

八、路径参数和查询参数一起用

from typing import Annotated

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/users/{user_id}/orders")
def list_user_orders(
    user_id: int,
    status: Annotated[str | None, Query(description="订单状态")] = None,
    page: Annotated[int, Query(ge=1)] = 1,
):
    return {
        "user_id": user_id,
        "status": status,
        "page": page,
    }

访问:

GET /users/1/orders?status=paid&page=2

参数来源:

参数来源
user_id路径 /users/{user_id}
status查询参数 ?status=paid
page查询参数 ?page=2