FastAPI 系列

  1. FastAPI 系列:从第一个接口到生产部署

  2. FastAPI 为什么适合做 JSON API

  3. 第一个接口怎么跑起来

  4. 路径、查询和请求体为什么要分开声明

  5. Pydantic 模型怎么当契约

  6. 路由怎么拆(当前篇)

  7. 依赖注入到底省了什么

  8. 数据库会话怎么进接口

  9. 状态码和异常为什么不要裸 raise

  10. 鉴权怎么接到 Depends 上

  11. 中间件、CORS 和后台任务分别解决什么

  12. 测试怎么写才不连真实库

  13. 生产怎么部署

main.py 超过两三个资源,就该拆。FastAPI 的拆分单位是 APIRouter:一组路径共享前缀、标签和依赖,再 include_router 进应用。

FastAPI 应用 include 多个带前缀的 APIRouter

推荐的目录

app/
  __init__.py
  main.py
  dependencies.py
  routers/
    items.py
    users.py
  models/
    item.py
    user.py

应用对象只负责组装:中间件、异常处理、挂路由。业务路径不要继续往 main.py 堆。

定义 Router

from fastapi import APIRouter, HTTPException

router = APIRouter(prefix="/items", tags=["items"])

fake_items_db = {"plumbus": {"name": "Plumbus"}}


@router.get("/")
async def read_items():
    return fake_items_db


@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id not in fake_items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item_id": item_id, **fake_items_db[item_id]}

prefix 不要在每个装饰器里重复写 /itemstags 会成为 Swagger UI 的分组名。

挂到应用上

from fastapi import FastAPI

from app.routers import items, users

app = FastAPI()
app.include_router(items.router)
app.include_router(users.router)

还可以二次加前缀,例如 app.include_router(items.router, prefix="/api/v1")。版本前缀放在组装处,比写死在每个文件里容易改。

路由级依赖

from fastapi import APIRouter, Depends

from app.dependencies import get_token_header

router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
)

写在 Router 上的 dependencies 不会注入到函数参数里,只保证「这组路由先跑这些依赖」。适合整组都要登录,但不需要在每个函数里声明 user

常见误区

两个 Router 注册了同一路径

后注册的不一定覆盖得干净,OpenAPI 里也会出现重复。按资源拆文件,前缀不要重叠。

为了「微服务」把每个函数拆成一个 Router

拆分粒度是资源或限界上下文,不是函数个数。

在 Router 文件里创建 FastAPI()

测试和部署会导入到多个应用实例。全项目只在 main.py 创建一次 app

小结

Router 解决的是模块边界:前缀、文档分组、整组鉴权。下一篇把数据库会话和公共逻辑放进 Depends,让路由函数变薄。

参考资料