FastAPI 路径参数与查询参数详解
FastAPI 中,客户端向服务端传递数据主要通过两种参数:路径参数(Path Parameters)和查询参数(Query Parameters)。路径参数是 URL 路径的一部分,通常用于标识资源;查询参数跟在 ? 后面,常用于过滤、排序等可选条件。下面逐一讲解。
路径参数
路径参数写在 URL 路径中,使用 {} 占位,函数参数名与之对应即可。
基本用法
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id}
访问 /users/42 时,user_id 会自动转为 int 类型。如果传入非数字如 /users/abc,FastAPI 会自动返回 422 校验错误。
类型校验
FastAPI 会根据类型注解自动做类型转换和校验:
@app.get("/items/{item_id}")
async def get_item(item_id: int):
# item_id 一定是个 int,否则直接返回 422
return {"item_id": item_id, "type": type(item_id).__name__}
支持的类型包括 int、float、str、bool、UUID 等。
路径参数的顺序
注意:固定路径必须定义在动态路径之前,否则会被动态路径拦截:
# ✅ 正确:固定路径在前
@app.get("/users/me")
async def get_current_user():
return {"username": "admin"}
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id}
# ❌ 错误:如果 /users/{user_id} 在前,访问 /users/me 时 "me" 会被当成 user_id
使用 Path 做额外校验
from fastapi import Path
@app.get("/articles/{article_id}")
async def get_article(
article_id: int = Path(
..., # ... 表示必填
title="文章ID",
description="要获取的文章编号",
ge=1, # >= 1
le=10000, # <= 10000
)
):
return {"article_id": article_id}
Path 常用校验参数:
| 参数 | 说明 |
|---|---|
... |
必填(省略号) |
ge / gt |
大于等于 / 大于 |
le / lt |
小于等于 / 小于 |
min_length / max_length |
字符串最小/最大长度 |
regex |
正则匹配(FastAPI 旧版) |
pattern |
正则匹配(Pydantic v2) |
title / description |
文档展示用 |
枚举类型的路径参数
from enum import Enum
class CategoryEnum(str, Enum):
tech = "tech"
life = "life"
travel = "travel"
@app.get("/posts/{category}")
async def get_posts(category: CategoryEnum):
# 自动生成文档,且只接受这三个值
return {"category": category}
访问 /posts/tech 正常返回;访问 /posts/music 返回 422。
查询参数
查询参数是 URL 中 ? 后面的键值对,如 ?page=1&size=20。FastAPI 中,函数参数不在路径中且不是 Body 类型,就会被自动识别为查询参数。
基本用法
@app.get("/posts")
async def list_posts(page: int = 1, size: int = 10):
return {"page": page, "size": size}
访问 /posts?page=2&size=5,page=2, size=5;不传参数则使用默认值。
可选查询参数
from typing import Optional
@app.get("/search")
async def search(
keyword: Optional[str] = None,
category: Optional[str] = None,
):
result = {"keyword": keyword, "category": category}
if keyword:
result["match"] = f"搜索: {keyword}"
return result
Optional[str] = None 表示该参数可选,不传时为 None。
使用 Query 做额外校验
from fastapi import Query
@app.get("/items")
async def list_items(
offset: int = Query(default=0, ge=0, description="偏移量"),
limit: int = Query(default=10, ge=1, le=100, description="每页数量"),
sort: Optional[str] = Query(default=None, pattern=r"^(asc|desc)$", description="排序方式"),
):
return {"offset": offset, "limit": limit, "sort": sort}
Query 支持与 Path 几乎相同的校验参数。
接收多个同名查询参数
from typing import List
@app.get("/filter")
async def filter_items(tags: List[str] = Query(default=[])):
"""
示例: /filter?tags=python&tags=fastapi&tags=web
结果: tags = ["python", "fastapi", "web"]
"""
return {"tags": tags}
布尔类型查询参数
@app.get("/products")
async def list_products(in_stock: bool = False):
"""
访问: /products?in_stock=true → True
/products?in_stock=1 → True
/products?in_stock=yes → True
/products?in_stock=on → True
/products → False(默认值)
"""
return {"in_stock": in_stock}
路径参数与查询参数的组合
最常见的场景是路径参数标识资源,查询参数做筛选:
@app.get("/users/{user_id}/posts")
async def get_user_posts(
user_id: int = Path(..., ge=1),
page: int = Query(default=1, ge=1),
size: int = Query(default=20, ge=1, le=100),
status: Optional[str] = Query(default=None, pattern=r"^(draft|published|archived)$"),
):
"""
获取某个用户的文章列表
- **user_id**: 用户ID(路径参数)
- **page**: 页码(查询参数,默认第1页)
- **size**: 每页数量(查询参数,默认20,最大100)
- **status**: 文章状态过滤(可选)
"""
return {
"user_id": user_id,
"page": page,
"size": size,
"status": status,
}
请求示例:/users/42/posts?page=2&size=5&status=published
小结
| 特性 | 路径参数 | 查询参数 |
|---|---|---|
| 位置 | URL 路径中 /users/{id} |
URL ? 后面 ?key=val |
| 用途 | 标识资源 | 过滤、排序、分页 |
| 必填 | 默认必填 | 默认可选 |
| 校验工具 | Path() |
Query() |
| 类型 | str / int / UUID / Enum | str / int / bool / List 等 |
掌握路径参数和查询参数是 FastAPI 开发的基础,配合 Path 和 Query 的校验能力,可以在不写额外逻辑的情况下完成大部分参数校验工作,并自动生成清晰的 API 文档。
- 点赞
- 收藏
- 关注作者
评论(0)