🐸 青蛙编程网
首页 / Python / FastAPI / 3. 路由与参数

路由与参数

这是什么:路由与参数 = 一个网址一个函数的基础上,让 URL 里携带信息:/items/5 里的 5、?skip=0&limit=10 里的分页值,都会自动变成函数参数。

为什么用:真实接口全是「带参」的:查第 3 页、找 id 为 42 的订单。FastAPI 从函数签名就能声明参数类型,非法值自动拦截——这正是它「签名即文档」的主场。

如何用:路径参数写进路由字符串、查询参数用带默认值的函数参数,本章顺手体验一次 422 自动校验。

路径参数:URL 的一部分

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}

路由字符串里的 {item_id} 是占位符:访问 /items/5 时,FastAPI 把 5 取出来交给 item_id。关键在类型注解 int——它会被自动转换并校验:

GET /items/5    → {"item_id": 5}        ✅ "5" 转成了整数 5
GET /items/abc  → 422 错误 + 明细        ❌ "abc" 不是整数,自动拦截

不用手写 int()、不用手写 try/except——注解就是校验器,这就是第 1 章说的「类型注解在打工」。

查询参数:问号后面的键值对

不在路由里声明、函数签名里带默认值的参数,自动成为查询参数:

@app.get("/items")
def list_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}
GET /items                      → {"skip": 0, "limit": 10}   全用默认值
GET /items?skip=20&limit=5      → {"skip": 20, "limit": 5}   自动转成 int
GET /items?skip=abc             → 422                        类型不对自动拦

?key=value&key2=value2 是 URL 标准写法(AJAX 教程里 GET 请求拼的就是它)。区分规则一句话:写在路由 {} 里的是路径参数,签名里带默认值的是查询参数。

两类参数混着用

@app.get("/users/{user_id}/posts")
def user_posts(user_id: int, tag: str = "all", only_first: bool = False):
    return {"user_id": user_id, "tag": tag, "only_first": only_first}
GET /users/7/posts?tag=python&only_first=true
→ {"user_id": 7, "tag": "python", "only_first": True}

注意 bool 也支持:URL 里写 true / false(或 1 / 0),FastAPI 自动转成 Python 的 True / False。

async def 什么时候用

函数签名前加 async def 就是异步函数,适合里面有「等网络 / 等数据库」的异步操作(如 await 调用异步库)。入门阶段用普通 def 完全没问题——FastAPI 会自动把 def 路由丢进线程池,不阻塞服务。规则:用到异步库才写 async,拿不准就用 def。

记忆口诀:路由花括号装路径,签名默认值变查询;类型写对它把关门,写错直接 422。

❓ 常见问题

Q1:422 报错的响应长什么样?

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

loc 告诉你哪个参数出错(path = 路径参数),msg 说明原因。这是自动校验的标配输出,看到 422 先读 detail。

Q2:路由 /items/{item_id} 和 /items/me 同时存在,访问谁?

两个都能注册。FastAPI 按声明顺序匹配:如果 /items/me 的路由写在前面,me 就走它;写在后面则会被 {item_id} 抢走(还因 me 转 int 失败报 422)。固定路径放前面,带参数的放后面。

Q3:忘了写类型注解会怎样?

def read_item(item_id) 没有 : int 时,参数被当成字符串处理,/items/5 拿到的是 "5"——不报错,但数学运算会炸。路径参数一定写注解,这是 FastAPI 的正确打开方式。

📝 本章小结

  • 路径参数:路由里 {name} 占位,配合类型注解自动转换与校验
  • 查询参数:签名里带默认值的参数,?a=1&b=2 传入,bool 也自动转
  • 非法输入统一 422,detail 里带出错参数与原因
  • async def 用于异步库场景;普通 def 不阻塞,入门放心用

动手改

  1. 给 read_item 加一个查询参数 verbose: bool = False,为 true 时多返回一个字段
  2. 写一个 /items/me 路由,分别放在 {item_id} 前面和后面,体会匹配顺序
  3. 故意访问 /items/3.14,看看 422 的 detail 说什么

上一章:第一个应用 · 下一章:请求体与 Pydantic 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。