第 07 章 路由 Router
学习目标
学完本章,你应该能:
- 理解路由的作用,掌握 RESTful API 规范
- 掌握 fba 的路由目录结构和注册方式
- 能自己定义并注册一个接口
一、路由是什么
路由(Router) 是"URL 地址"和"处理函数"之间的映射。它决定了:当用户访问某个 URL 时,应该调用哪个函数来处理。
比如:
GET /api/v1/user/1 → 查询用户1
POST /api/v1/user → 创建用户
PUT /api/v1/user/1 → 更新用户1
DELETE /api/v1/user/1 → 删除用户1fba 的路由遵循 RESTful API 规范。
RESTful:一种 API 设计风格,用 HTTP 方法(GET/POST/PUT/DELETE)表达对资源的操作,URL 用名词表示资源。
URL 与函数的映射关系
二、路由目录结构
fba 的路由结构很规范,分为两种情况:
情况 1:业务含子包(如 admin)
backend/app/admin/
├── api/
│ └── v1/
│ ├── sys/
│ │ ├── user/
│ │ │ ├── __init__.py # 注册子包内所有路由
│ │ │ └── user.py # 定义具体接口
│ │ └── ...
│ ├── __init__.py
│ └── router.py # 注册所有子包的路由情况 2:业务不含子包
backend/app/xxx/
├── api/
│ └── v1/
│ ├── __init__.py
│ ├── xxx.py # 定义具体接口
│ └── router.py # 注册所有路由三、定义接口(APIRouter)
fba 用 FastAPI 的 APIRouter 来组织路由。一个典型的接口文件:
python
from fastapi import APIRouter
router = APIRouter()
@router.get('/{user_id}', summary='获取用户详情')
async def get_user(user_id: int):
...关键点:
- 路由变量统一命名为
router(这是 fba 的约定) - 每个接口用
summary参数写清楚功能,方便生成文档
四、注册路由(重点:导入方式)
fba 有一个非常重要的约定:注册路由时的导入方式。
因为所有路由变量都叫 router,导入时必须用 as 起别名避免冲突:
python
from backend.app.admin.api.v1.sys.user import router as user_router在 router.py 中统一注册:
python
from fastapi import APIRouter
from backend.app.admin.api.v1.sys.user import router as user_router
v1 = APIRouter()
v1.include_router(user_router, prefix='/users', tags=['用户管理'])记住:务必用
import router as xxx_router的方式导入,这是 fba 的路由铁律。
五、路由层级关系
fba 的路由是多层嵌套的,最终拼成完整的 URL:
顶级 router(backend/app/router.py)
└── admin 的 router(app/admin/router.py)
└── v1 的 router(api/v1/router.py)
└── sys 的 router(api/v1/sys/__init__.py)
└── user 的 router(user.py 里的具体接口)每一层都可以加 prefix(路径前缀),最终拼出类似 /api/v1/admin/sys/user/1 的完整路径。
路由层级与 URL 拼接
六、常见 HTTP 方法
| 方法 | 用途 | 对应操作 |
|---|---|---|
| GET | 查询 | Read |
| POST | 新增 | Create |
| PUT / PATCH | 更新 | Update |
| DELETE | 删除 | Delete |
七、完整示例:用户接口
python
# backend/app/admin/api/v1/sys/user.py
from fastapi import APIRouter
from backend.app.admin.schema.user import CreateUserParam, GetUserDetail
from backend.common.response.response_model import ResponseModel
router = APIRouter()
@router.get('/{user_id}', summary='获取用户详情', response_model=ResponseModel)
async def get_user(user_id: int):
# 这里调用 service 层
return response_base.success(data={'id': user_id})
@router.post('', summary='创建用户')
async def create_user(obj: CreateUserParam):
return response_base.success()八、常见疑问
Q1:为什么要统一命名为 router? 为了规范一致,看到 router 就知道这是路由对象,减少理解成本。代价是导入时要起别名。
Q2:prefix 和路由装饰器里的路径是什么关系? 最终 URL = 所有层级的 prefix 拼接 + 装饰器里的路径。比如 prefix='/users' + @router.get('/{id}') = /users/{id}。
本章小结
关键要点回顾:
- 路由是 URL 到处理函数的映射,遵循 RESTful 规范
- 路由变量统一命名为
router - 注册时必须
import router as xxx_router起别名 - 路由多层嵌套,通过
prefix拼路径 - 每个接口写
summary说明功能
下一步: 路由定义好了,但真正的逻辑在 Service 和 CRUD 层,第 08 章深入讲解。
对应官方文档:
路由(backend/reference/router.html)