#路径参数与查询参数
#一、路径参数(Path Parameters)
路径参数是 URL 路径的一部分,用于标识资源。
#基本用法
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}访问:GET /items/42 → {"item_id": 42}
#自动类型转换
FastAPI 根据类型提示自动转换:
@app.get("/items/{item_id}")
async def read_item(item_id: int):
# item_id 自动转为 int
return {"item_id": item_id, "type": type(item_id).__name__}
# GET /items/42 → {"item_id": 42, "type": "int"}
# GET /items/foo → 422 错误(不是有效整数)#路径参数验证
使用 Path 进行更严格的验证:
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(
gt=0, # 大于 0
le=1000, # 小于等于 1000
title="项目ID",
description="要查询的项目 ID,必须是 1-1000 之间的整数"
)
):
return {"item_id": item_id}#路径参数包含路径
如果路径参数本身包含路径(如文件路径),使用 path 类型:
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
# GET /files/home/user/data.txt
# → {"file_path": "home/user/data.txt"}#二、查询参数(Query Parameters)
查询参数在 URL 的 ? 之后,以 key=value 形式传递。
#基本用法
@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
# GET /items/ → {"skip": 0, "limit": 10}
# GET /items/?skip=20 → {"skip": 20, "limit": 10}
# GET /items/?skip=20&limit=5 → {"skip": 20, "limit": 5}#可选查询参数
使用 | None 或 Optional 表示可选:
from typing import Annotated
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
# GET /items/42 → {"item_id": 42}
# GET /items/42?q=hi → {"item_id": 42, "q": "hi"}#必需查询参数
不提供默认值即为必需:
@app.get("/items/")
async def read_items(q: str): # 无默认值,必需
return {"q": q}
# GET /items/?q=search → {"q": "search"}
# GET /items/ → 422 错误(缺少必需参数)#查询参数验证
使用 Query 进行验证:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str | None = Query(
default=None,
max_length=50, # 最大长度
min_length=3, # 最小长度
pattern="^[a-z]+$" # 正则匹配(只允许小写字母)
)
):
return {"q": q}#查询参数列表
接收多个同名参数:
@app.get("/items/")
async def read_items(q: list[str] = Query(default=[])):
return {"q": q}
# GET /items/?q=foo&q=bar
# → {"q": ["foo", "bar"]}#三、参数顺序规则
FastAPI 能识别参数类型,但推荐按以下顺序定义:
@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
# 1. 路径参数(按 URL 中的顺序)
user_id: int,
item_id: int,
# 2. 查询参数
q: str | None = None,
short: bool = False
):
return {"user_id": user_id, "item_id": item_id, "q": q, "short": short}#四、参数验证详解
#Path 验证参数
from fastapi import Path
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(
gt=0, # 大于
ge=1, # 大于等于
lt=1000, # 小于
le=999, # 小于等于
title="项目ID",
description="项目唯一标识符"
)
):
return {"item_id": item_id}#Query 验证参数
from fastapi import Query
from typing import Annotated
@app.get("/items/")
async def read_items(
q: Annotated[str | None, Query(
max_length=50,
min_length=3,
pattern="^[a-zA-Z]+$",
title="搜索关键词",
description="用于搜索的关键词,3-50 个字母"
)] = None
):
return {"q": q}#数值验证示例
@app.get("/items/")
async def read_items(
skip: int = Query(default=0, ge=0), # 非负整数
limit: int = Query(default=10, gt=0, le=100) # 1-100
):
return {"skip": skip, "limit": limit}#五、Annotated 写法(推荐)
Python 3.9+ 推荐使用 Annotated,将验证规则与类型分离:
from typing import Annotated
from fastapi import FastAPI, Query, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: Annotated[int, Path(gt=0, le=1000)],
q: Annotated[str | None, Query(max_length=50)] = None,
size: Annotated[int, Query(gt=0, le=100)] = 10
):
return {"item_id": item_id, "q": q, "size": size}优势:
- 类型与验证规则分离,更清晰
- 可复用验证规则
- 编辑器智能提示更好
#六、参数别名
当查询参数名与 Python 关键字冲突时,使用 alias:
@app.get("/items/")
async def read_items(
item_query: str = Query(alias="item-query") # URL 中用 item-query
):
return {"item_query": item_query}
# GET /items/?item-query=search#七、参数弃用标记
标记即将废弃的参数:
@app.get("/items/")
async def read_items(
q: str | None = Query(
default=None,
deprecated=True, # 标记为废弃
description="已废弃,请使用 search 参数"
),
search: str | None = None
):
return {"q": q, "search": search}Swagger UI 会显示删除线提示。
#八、完整示例
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
# 路径参数
user_id: Annotated[int, Path(
gt=0,
title="用户ID",
description="用户的唯一标识符"
)],
item_id: Annotated[int, Path(
gt=0,
title="项目ID",
description="项目的唯一标识符"
)],
# 查询参数
q: Annotated[str | None, Query(
max_length=50,
title="搜索关键词"
)] = None,
short: bool = Query(
default=False,
description="是否返回简化信息"
),
size: Annotated[int, Query(gt=0, le=100)] = 10
):
item = {"item_id": item_id, "owner_id": user_id}
if q:
item.update({"q": q})
if not short:
item.update({
"description": "这是一个很长的描述...",
"size": size
})
return item#九、错误处理
FastAPI 自动返回 422 错误(Unprocessable Entity):
{
"detail": [
{
"loc": ["path", "item_id"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}#自定义错误消息
from fastapi import FastAPI, Path, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int = Path(gt=0)):
if item_id > 100:
raise HTTPException(
status_code=404,
detail=f"Item {item_id} not found"
)
return {"item_id": item_id}#十、小结
| 参数类型 | 定义方式 | 示例 |
|---|---|---|
| 路径参数 | {param} | @app.get("/items/{item_id}") |
| 必需查询参数 | 无默认值 | q: str |
| 可选查询参数 | = None | q: str | None = None |
| 默认值参数 | = value | limit: int = 10 |
| 验证参数 | Query() / Path() | Query(max_length=50) |
| 列表参数 | list[str] | q: list[str] = Query(default=[]) |

