第4章 - 路径参数
嗨,朋友!我是长安。
这一章我来讲讲路径参数。这是我当年学习的时候觉得特别实用的一个功能,几乎每个接口都会用到!
🎯 本章目标
- 理解什么是路径参数
- 学会定义和使用路径参数
- 掌握路径参数的类型验证
- 学会使用枚举限制参数值
1️⃣ 什么是路径参数?
路径参数就是 URL 路径中的变量部分。举个例子你就懂了:
比如:
/users/1- 获取 ID 为 1 的用户/users/2- 获取 ID 为 2 的用户/products/abc123- 获取编号为 abc123 的商品
这里的 1、2、abc123 就是路径参数。
2️⃣ 定义路径参数
使用 {参数名} 的方式在路径中定义参数:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id):
return {"user_id": user_id}
访问 http://127.0.0.1:8000/users/123,返回:
{"user_id": "123"}
长安提醒
默认情况下,路径参数是字符串类型! 这是很多新手容易忽略的地方,我当年也踩过坑。
3️⃣ 指定��数类型
通过类型注解指定参数类型,FastAPI 会自动进行类型转换和验证:
@app.get("/users/{user_id}")
def get_user(user_id: int): # 指定为 int 类型
return {"user_id": user_id, "type": type(user_id).__name__}
访问 http://127.0.0.1:8000/users/123,返回:
{"user_id": 123, "type": "int"}
类型验证
如果传入的参数不能转换为指定类型,FastAPI 会自动返回错误:
访问 http://127.0.0.1:8000/users/abc,返回:
{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "user_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "abc"
}
]
}
4️⃣ 常用参数类型
from fastapi import FastAPI
app = FastAPI()
# 整数类型
@app.get("/items/{item_id}")
def get_item(item_id: int):
return {"item_id": item_id}
# 字符串类型
@app.get("/users/{username}")
def get_user(username: str):
return {"username": username}
# 浮点数类型
@app.get("/prices/{price}")
def get_price(price: float):
return {"price": price}
# 布尔类型
@app.get("/status/{is_active}")
def get_status(is_active: bool):
return {"is_active": is_active}
布尔类型的特殊处理
FastAPI 对布尔类型很智能,以下值都会被识别为 True:
true、True、TRUE1yes、Yes、YESon、On、ON
以下值会被识别为 False:
false、False、FALSE0no、No、NOoff、Off、OFF
# 访问 /status/true -> {"is_active": true}
# 访问 /status/yes -> {"is_active": true}
# 访问 /status/1 -> {"is_active": true}
# 访问 /status/false -> {"is_active": false}
# 访问 /status/no -> {"is_active": false}
5️⃣ 多个路径参数
可以定义多个路径参数:
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(user_id: int, post_id: int):
return {
"user_id": user_id,
"post_id": post_id
}
访问 http://127.0.0.1:8000/users/1/posts/100,返回:
{"user_id": 1, "post_id": 100}
6️⃣ 路径顺序很重要!
长安的重要提醒
路径的定义顺序非常非常重要!FastAPI 会按顺序匹配路径。 这是我当年花了好几个小时才找到的坑,你一定要注意!
# ❌ 错误示例
@app.get("/users/{user_id}")
def get_user(user_id: str):
return {"user_id": user_id}
@app.get("/users/me") # 这个永远不会被匹配到!
def get_current_user():
return {"user": "当前用户"}
因为 /users/me 会先被 /users/{user_id} 匹配,me 会被当作 user_id。
# ✅ 正确示例
@app.get("/users/me") # 固定��径放前面
def get_current_user():
return {"user": "当前用户"}
@app.get("/users/{user_id}") # 动态路径放后面
def get_user(user_id: str):
return {"user_id": user_id}
7️⃣ 使用枚举限制参数值
有时候我们希望参数只能是特定的几个值,可以使用枚举:
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
# 定义枚举类
class Gender(str, Enum):
male = "male"
female = "female"
other = "other"
@app.get("/users/gender/{gender}")
def get_users_by_gender(gender: Gender):
return {"gender": gender, "message": f"获取性别为 {gender.value} 的用户"}
现在 gender 参数只能是 male、female 或 other:
- 访问
/users/gender/male✅ - 访问
/users/gender/female✅ - 访问
/users/gender/abc❌ 返回错误
枚举的好处
- 自动验证 - 只接受定义的值
- 文档清晰 - 在 Swagger UI 中会显示可选值
- 代码提示 - IDE 会提示可用的值
更多枚举示例
from enum import Enum
# 订单状态
class OrderStatus(str, Enum):
pending = "pending" # 待支付
paid = "paid" # 已支付
shipped = "shipped" # 已发货
delivered = "delivered" # 已送达
cancelled = "cancelled" # 已取消
@app.get("/orders/status/{status}")
def get_orders_by_status(status: OrderStatus):
return {"status": status.value}
# 文章分类
class Category(str, Enum):
tech = "tech"
life = "life"
travel = "travel"
@app.get("/articles/category/{category}")
def get_articles(category: Category):
return {"category": category.value}
8️⃣ 使用 Path 进行更多验证
使用 Path 可以对路径参数进行更详细的验证:
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
def get_item(
item_id: int = Path(
title="商品ID",
description="商品的唯一标识符",
ge=1, # 大于等于 1
le=10000, # 小于等于 10000
example=42 # 示例值
)
):
return {"item_id": item_id}
Path 的常用参数
| 参数 | 说明 | 示例 |
|---|---|---|
title | 参数标题 | title="用户ID" |
description | 参数描述 | description="用户的唯一标识" |
ge | 大于等于 | ge=1 |
gt | 大于 | gt=0 |
le | 小于等于 | le=100 |
lt | 小于 | lt=100 |
example | 示例值 | example=42 |
字符串长度验证
@app.get("/users/{username}")
def get_user(
username: str = Path(
min_length=3, # 最小长度
max_length=20, # 最大长度
pattern="^[a-zA-Z0-9_]+$" # 正则表达式
)
):
return {"username": username}
9️⃣ 完整示例
from enum import Enum
from fastapi import FastAPI, Path
app = FastAPI(title="路径参数示例")
# 用户角色枚举
class UserRole(str, Enum):
admin = "admin"
user = "user"
guest = "guest"
# 模拟数据
fake_users = {
1: {"id": 1, "name": "张三", "role": "admin"},
2: {"id": 2, "name": "李四", "role": "user"},
3: {"id": 3, "name": "王五", "role": "guest"},
}
@app.get("/")
def home():
return {"message": "路径参数示例"}
# 基本路径参数
@app.get("/users/{user_id}", tags=["用户"])
def get_user(user_id: int):
"""根据ID获取用户"""
if user_id in fake_users:
return fake_users[user_id]
return {"error": "用户不存在"}
# 使用 Path 验证
@app.get("/items/{item_id}", tags=["商品"])
def get_item(
item_id: int = Path(
title="商品ID",
description="商品的唯一标识符,范围1-9999",
ge=1,
le=9999,
example=100
)
):
"""获取商品信息"""
return {"item_id": item_id, "name": f"商品{item_id}"}
# 使用枚举
@app.get("/users/role/{role}", tags=["用户"])
def get_users_by_role(role: UserRole):
"""根据角色获取用户"""
result = [u for u in fake_users.values() if u["role"] == role.value]
return {"role": role.value, "users": result}
# 多个路径参数
@app.get("/departments/{dept_id}/employees/{emp_id}", tags=["部门"])
def get_employee(dept_id: int, emp_id: int):
"""获取部门下的员工"""
return {
"department_id": dept_id,
"employee_id": emp_id
}
# 固定路径优先
@app.get("/articles/latest", tags=["文章"])
def get_latest_article():
"""获取最新文章"""
return {"title": "最新文章", "id": 999}
@app.get("/articles/{article_id}", tags=["文章"])
def get_article(article_id: int):
"""根据ID获取文章"""
return {"id": article_id, "title": f"文章{article_id}"}
📝 小结
本章我们学习了:
- ✅ 路径参数的定义方式
{param} - ✅ 类型注解和自动验证
- ✅ 多个路径参数
- ✅ 路径顺序的重要性
- ✅ 使用枚举限制参数值
- ✅ 使用 Path 进行详细验证
🏃 下一步
路径参数学会了,但有时候我们需要传递可选参数,比如分页、排序等。下一章学习查询参数!
💪 练习题
创建一个接口
/products/{product_id},要求 product_id 必须是 1-1000 之间的整数创建一个订单状态枚举,包含:pending、processing、completed、cancelled,然后创建接口
/orders/status/{status}根据状态查询订单创建接口
/categories/{category_id}/products/{product_id},获取某分类下的某商品
参考答案
from enum import Enum
from fastapi import FastAPI, Path
app = FastAPI()
# 练习1
@app.get("/products/{product_id}")
def get_product(
product_id: int = Path(ge=1, le=1000)
):
return {"product_id": product_id}
# 练习2
class OrderStatus(str, Enum):
pending = "pending"
processing = "processing"
completed = "completed"
cancelled = "cancelled"
@app.get("/orders/status/{status}")
def get_orders(status: OrderStatus):
return {"status": status.value, "orders": []}
# 练习3
@app.get("/categories/{category_id}/products/{product_id}")
def get_category_product(category_id: int, product_id: int):
return {
"category_id": category_id,
"product_id": product_id
}
