跳到主要内容

2.1 路径参数

本章目标:学会在 URL 路径中定义动态参数,并利用类型注解自动校验。

1. 什么是路径参数

看这两个 URL:

GET /users/1 → 获取 id 为 1 的用户
GET /users/42 → 获取 id 为 42 的用户

路径中变化的那部分(1、42)就是路径参数。我们不可能为每个 id 写一个接口,所以要把它声明成变量:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id, "name": f"用户{user_id}"}

要点:

  • 路径中用 {user_id} 声明一个占位符
  • 函数参数写一个同名参数 user_id,FastAPI 自动把 URL 里的值传进来
  • : int 是类型注解,声明这个参数必须是整数

访问 http://127.0.0.1:8000/users/1 试试:

{"user_id": 1, "name": "用户1"}

2. 类型注解 = 自动校验 + 自动转换

试着访问 /users/abc(abc 不是整数),FastAPI 会自动返回 422 错误:

{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "user_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "abc"
}
]
}

你一行校验代码都没写,FastAPI 根据 : int 就完成了:

  1. 校验:不是合法整数直接拒绝,返回清晰的错误信息
  2. 转换:URL 里的一切本来都是字符串,"1" 被自动转成整数 1
  3. 文档:/docs 里会标明该参数是 integer 类型

这就是 FastAPI 的核心哲学:用 Python 类型注解驱动一切。常用类型:

@app.get("/items/{item_id}")
def get_item(item_id: int): ... # 整数

@app.get("/files/{file_name}")
def get_file(file_name: str): ... # 字符串(不写注解时默认也是 str)

@app.get("/price/{amount}")
def get_price(amount: float): ... # 小数

3. 多个路径参数

@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}

访问 /users/1/posts/99{"user_id": 1, "post_id": 99}

4. 路径顺序很重要(新手常见坑)

假设你想加一个「获取当前登录用户」的接口 /users/me

# ❌ 错误的顺序
@app.get("/users/{user_id}")
def get_user(user_id: int): ...

@app.get("/users/me")
def get_current_user(): ...

访问 /users/me 会报 422!因为 FastAPI 按声明顺序匹配路由/users/me 会先被 /users/{user_id} 匹配上,然后尝试把 "me" 转成 int 失败。

固定路径要写在动态路径前面:

# ✅ 正确的顺序
@app.get("/users/me")
def get_current_user(): ...

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

5. 用枚举限制取值范围

如果参数只允许几个固定值,用 Enum

from enum import Enum

class Category(str, Enum):
tech = "tech"
life = "life"
news = "news"


@app.get("/articles/{category}")
def list_articles(category: Category):
return {"category": category}
  • 访问 /articles/tech → 正常
  • 访问 /articles/xxx → 422,错误信息会列出所有合法取值
  • /docs 里该参数会变成下拉框,非常直观

继承 str, Enum 而不是只继承 Enum,是为了让它能直接序列化为 JSON 字符串。

6. 数值范围校验:Path

想限制 user_id 必须大于 0?用 Path 配合 Annotated

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}
  • ge=1:greater than or equal,大于等于 1。类似的还有 gt(大于)、le(小于等于)、lt(小于)
  • description 会显示在 /docs
  • Annotated[类型, 额外元数据] 是现代 FastAPI 的推荐写法,后面会大量使用,格式固定:参数名: Annotated[类型, Path(...)/Query(...)/...]

访问 /users/0 → 422:Input should be greater than or equal to 1

本章小结

  • 路径参数用 {名字} 声明,函数写同名参数接收
  • 类型注解自动完成校验、转换、文档生成
  • 固定路径必须写在动态路径之前
  • Enum 限制取值,用 Path(ge=..., le=...) 限制数值范围

下一章:2.2 查询参数