Appearance
28|路径参数与查询参数
HTTP 请求把数据传给后端有三种常见方式:URL 路径、查询字符串、请求体。路径参数用于标识资源(如文章 ID),查询参数用于过滤和分页(如 ?page=2)。这篇把这两种参数在 FastAPI 中的声明和校验讲清楚。
一、路径参数
路径参数写在 URL 路径中,用 {} 标记:
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/articles/{article_id}")
async def get_article(article_id: int):
return {"id": article_id}FastAPI 根据类型注解自动把路径中的字符串转成对应类型。访问 /articles/123 时,article_id 是整数 123;访问 /articles/abc 时,FastAPI 自动返回 422 错误,提示参数类型不匹配。
多个路径参数
python
@app.get("/users/{user_id}/orders/{order_id}")
async def get_order(user_id: int, order_id: int):
return {"user": user_id, "order": order_id}枚举约束
路径参数只能是固定值时,用 Enum 约束:
python
from enum import Enum
class Env(str, Enum):
dev = "dev"
test = "test"
prod = "prod"
@app.get("/config/{env}")
async def get_config(env: Env):
return {"env": env}访问 /config/dev 正常返回,访问 /config/invalid 返回 422,文档中也会列出允许的枚举值。
路径参数校验
python
from fastapi import Path
@app.get("/articles/{article_id}")
async def get_article(
article_id: int = Path(..., ge=1, description="文章ID")
):
return {"id": article_id}| 参数 | 作用 |
|---|---|
... | 必填( ellipsis 表示没有默认值) |
ge=1 | 必须大于等于 1 |
description | 文档中的描述 |
其他校验:gt(大于)、le(小于等于)、lt(小于)。
二、查询参数
查询参数写在 URL 的 ? 后面,用于过滤、排序、分页:
python
@app.get("/articles")
async def list_articles(
skip: int = 0,
limit: int = 20,
status: str | None = None,
):
return {"skip": skip, "limit": limit, "status": status}请求示例:
| URL | 参数值 |
|---|---|
/articles | skip=0, limit=20, status=None |
/articles?skip=10 | skip=10, limit=20, status=None |
/articles?limit=50&status=published | skip=0, limit=50, status="published" |
有默认值的查询参数是可选的,不传就用默认值。str | None = None 表示可选参数,不传时值为 None。
布尔查询参数
python
@app.get("/articles")
async def list_articles(active: bool = True):
return {"active": active}| URL | 参数值 |
|---|---|
/articles | True(默认值) |
/articles?active=true | True |
/articles?active=1 | True |
/articles?active=false | False |
/articles?active=0 | False |
查询参数校验
python
from fastapi import Query
@app.get("/articles")
async def list_articles(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
):
return {"skip": skip, "limit": limit}limit 的范围被限制在 1~100,防止前端传 limit=999999 拖垮数据库。
必填查询参数
python
@app.get("/search")
async def search(q: str): # 没有默认值,必填
return {"query": q}不传 q 时返回 422:
json
{"detail": [{"loc": ["query", "q"], "msg": "field required", "type": "value_error.missing"}]}三、路径参数 vs 查询参数
| 维度 | 路径参数 | 查询参数 |
|---|---|---|
| 位置 | URL 路径中 | ? 后面 |
| 必填性 | 必填(URL 结构决定) | 通常可选 |
| 用途 | 标识资源 | 过滤、排序、分页、配置 |
| 示例 | /articles/123 | /articles?page=2 |
RESTful 设计中,路径参数是 URL 的结构性部分,删掉后 URL 就不完整;查询参数是附加信息,删掉后资源本身仍能访问。
四、常见错误
路径参数和函数参数名不一致
python
# 错误:路径中叫 article_id,函数参数叫 id
@app.get("/articles/{article_id}")
async def get_article(id: int): # FastAPI 找不到 article_id 对应的参数
return {"id": id}
# 正确:名字一致
@app.get("/articles/{article_id}")
async def get_article(article_id: int):
return {"id": article_id}路径参数没有类型注解
python
# 错误:没有类型注解,FastAPI 不会校验,文档中显示为 string
@app.get("/articles/{id}")
async def get_article(id):
return {"id": id}
# 正确
@app.get("/articles/{id}")
async def get_article(id: int):
return {"id": id}查询参数没有设上限
python
# 危险:limit 无上限,数据库可能返回海量数据
@app.get("/articles")
async def list_articles(limit: int = 20):
...
# 正确:限制最大值
@app.get("/articles")
async def list_articles(limit: int = Query(20, ge=1, le=100)):
...