首页 / FastAPI 入门教程 / 路径参数 Path Parameters

FastAPI 入门教程

路径参数 Path Parameters

本教程共 50 篇 · 第 6 篇 · 更新于 2026-08-12 · 约 7 分钟阅读

FastAPIFastAPI 入门教程路径参数Path Parameters类型校验自动文档

本节目标:学会用 {id} 在 URL 里放动态参数,理解「声明类型就等于自动校验」,并能看懂报错和文档。

在前面几章里,我们的接口地址都是写死的,比如 //items/。真实的接口往往要处理「不同的东西」,例如查看 id 为 5 的商品、查看 id 为 99 的用户。这个会变化的部分,就是路径参数。

6-1 用花括号声明路径参数

路径参数写在路由地址的花括号 {} 里。它的名字要和函数参数的名字一样,FastAPI 就会自动把 URL 里的值传进函数。

from fastapi import FastAPI

app = FastAPI()


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

把这段代码保存为 main.py,用下面命令启动(开发模式带热重载):

fastapi dev main.py

打开浏览器访问 http://127.0.0.1:8000/items/foo,你会看到返回:

{"item_id": "foo"}

这里 foo 就是路径参数 item_id 的值。它现在是个字符串,因为函数参数 item_id 没有写类型。

Tip

等价启动命令还有 uvicorn main:app --reload。我们默认推荐 fastapi dev,它是 FastAPI 官方 CLI,输出更友好。

6-2 声明类型,自动完成转换

FastAPI 最爽的一点:你只要给参数写一个 Python 类型,它就帮你把 URL 里的字符串转成对应类型。下面把 item_id 声明成 int

from fastapi import FastAPI

app = FastAPI()


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

访问 http://127.0.0.1:8000/items/3,返回变成了:

{"item_id": 3}

注意返回的是整数 3,不是字符串 "3"。FastAPI 已经把来自 HTTP 请求的字符串 "3",自动解析成了 Python 的 int。你在函数内部拿到的就是真正的整数,可以直接做加减乘除。

6-3 声明类型,自动完成校验

类型不只是用来转换,还顺带做了校验。还是上面的代码,如果你访问 http://127.0.0.1:8000/items/foofoo 明显不是整数,FastAPI 会直接返回一个清晰的报错:

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

这个报错很有用:loc 告诉你出错位置是路径里的 item_idtype 告诉你错误类型;msg 是给人看的解释;input 是用户实际传的值。调试接口时这些信息能省不少时间。

如果你传的是小数,比如 http://127.0.0.1:8000/items/4.2,因为 4.2 也不是整数,同样会报类似的错。FastAPI 默认要求 int 就是整数。

6-4 文档里自动出现

光写一句 item_id: int,FastAPI 就帮你把参数类型写进了 OpenAPI 文档。启动后打开 http://127.0.0.1:8000/docs,你会看到可交互的 Swagger UI,里面明确标着 item_id 是整数类型,还能直接在网页上填值测试。

再到 http://127.0.0.1:8000/redoc 看另一套文档界面(ReDoc),同样是自动生成的。因为底层文档遵循 OpenAPI 标准,所以很多第三方工具也能直接读懂你的接口,甚至能自动生成各语言的客户端代码。

Note

所有这些能力——编辑器补全、数据转换、数据校验、自动文档——都来自同一行类型声明 item_id: int。你只写一次,好处全拿走。这是 FastAPI 相比很多框架最核心的优势。

这些校验的底层其实由 Pydantic 完成。FastAPI 把你的类型声明交给 Pydantic,由它负责把字符串解析成真正的 Python 类型并做校验,所以你享受的是经过大量实战检验的成熟能力,不用担心自己写的转换代码有疏漏。

6-5 声明的类型不止 int

除了 int,你还可以用其它标准 Python 类型,FastAPI 都会自动转换和校验:

类型说明访问示例
str字符串(不写类型时默认就是它)/items/foo
int整数/items/5
float浮点数/items/5.5
bool布尔值/items/true
uuid.UUIDUUID 标识/items/3fa85f64-5717-4562-b3fc-2c963f66afa6

比如把参数声明成 float

from fastapi import FastAPI

app = FastAPI()


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

访问 /items/3 会得到 3.0,访问 /items/4.2 会得到 4.2。更多复杂类型我们在后面章节继续展开。

6-6 多个路径参数一起用

一个地址里可以放多个路径参数,函数里按名字对应即可,顺序无所谓:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(user_id: int, item_id: str):
    return {"user_id": user_id, "item_id": item_id}

访问 http://127.0.0.1:8000/users/5/items/pen,返回:

{"user_id": 5, "item_id": "pen"}

FastAPI 靠「名字」认参数,不靠位置,所以你写成 async def read_user_item(item_id: str, user_id: int) 也没问题。

6-7 路由顺序很重要

当你同时有「固定路径」和「带参数的路径」时,定义顺序会决定谁能匹配到。看这个例子:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: int):
    return {"user_id": user_id}

访问 /users/me 时,FastAPI 从上往下匹配,先命中 /users/me,返回当前用户。如果把这两段顺序反过来,/users/me 会被 /users/{user_id} 抢走,FastAPI 会以为 user_id 的值是字符串 "me",然后因为 "me" 不是整数而报错。

Note

固定路径一定要写在「带参数的路径」前面,否则动态参数会把固定值吞掉。这是新手最常踩的坑。

同一个路径也不要重复注册两次。若你为 /users/{user_id} 写了两个处理函数,后一个不会覆盖前一个,而是永远轮不到执行,因为匹配在第一个就停下了。这类问题不会报错,只会表现为”改了代码却没生效”,排查时优先检查是否有更靠前的路径把请求截住了。

6-8 小结

这一章你学会了路径参数的核心套路:用 {名字} 声明,用「和函数参数同名」接收;给参数写一个类型,FastAPI 就同时帮你做转换、校验、生成文档;访问 /docs 能在线调试;多个参数靠名字匹配、顺序随意;固定路由要放在动态路由之前。

下一章我们给路径参数加上更细的约束,比如整数必须大于 0、只能取几个固定值、甚至匹配带斜杠的路径。