前言
在构建中大型应用时,推荐使用 FastAPI 的 APIRouter
来组织路由,而不是直接在视图函数上使用装饰器。这是因为当业务功能和接口数量增多时,使用装饰器来组织路由会显得分散且难以维护。相比之下,APIRouter
提供了更好的模块化管理方式,使代码结构更加清晰和易于维护。
通过 APIRouter
,我们可以将相关的路由和业务逻辑分组,放在各自的模块中,方便团队协作开发和维护。这不仅提高了代码的可读性,还使得应用的扩展变得更加简单和灵活。
官方文档参考链接:FastAPI 官方文档 - Bigger Applications with Multiple Files
接下来,我们将通过一个 Demo 展示如何在 FastAPI 中使用 APIRouter
进行模块化路由管理。
工程目录
markdown
复制代码
├── api_router_demo 项目名称
├── handlers 路由处理模块
│ ├── __init__.py
│ ├── book.py
│ ├── movie.py
│ └── user.py
├── routers 路由模块
│ ├── __init__.py
│ ├── book.py
│ ├── movie.py
│ └── user.py
└── server.py 应用服务模块
应用主入口
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: server.py
# @Desc: { 应用服务模块 }
# @Date: 2024/06/28 11:35
import uvicorn
from fastapi import FastAPI
from contextlib import asynccontextmanager
from routers import api_router
@asynccontextmanager
async def lifespan(app: FastAPI):
await startup()
yield
await shutdown()
app = FastAPI(lifespan=lifespan, description="APIRouter模块路由Demo")
# app = FastAPI(lifespan=lifespan, routes=api_router.routes, description="APIRouter模块路由Demo")
async def startup():
# 初始化路由
app.include_router(api_router)
# 初始化资源...
async def shutdown():
print("释放资源")
print("Shutting down...")
def main():
uvicorn.run(app)
if __name__ == '__main__':
main()
主入口就简单的通过 app.include_router(api_router)
初始化一些路由资源
也可以构造FastAPI应用时入参指定
python
复制代码
app = FastAPI(lifespan=lifespan, routes=api_router.routes, description="APIRouter模块路由Demo")
具体路由信息在 routers 包下
路由模块
用户模块路由
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: user.py
# @Desc: { 用户模块路由 }
# @Date: 2024/06/28 11:47
from fastapi import APIRouter
from handlers import UserHandler
user_router = APIRouter()
user_router.add_api_route(
"/api/v1/users/register", UserHandler.register, methods=["POST"], summary="用户注册"
)
user_router.add_api_route(
"/api/v1/users/login", UserHandler.login, methods=["POST"], summary="用户登陆"
)
user_router.add_api_route(
"/api/v1/users", UserHandler.get_users, methods=["GET"], summary="获取用户列表"
)
user_router.add_api_route(
"/api/v1/users/{user_id}", UserHandler.get_user_detail, methods=["GET"], summary="用户详情"
)
图书模块路由
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: book.py
# @Desc: { 书籍模块路由 }
# @Date: 2024/06/28 11:48
from fastapi import APIRouter
from handlers import BookHandler
book_router = APIRouter()
book_router.add_api_route(
"/api/v1/books", BookHandler.get_books, methods=["GET"], summary="获取图书列表"
)
book_router.add_api_route(
"/api/v1/books/{book_id}", BookHandler.get_book_detail, methods=["GET"], summary="图书详情"
)
电影模块路由
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: movie.py
# @Desc: { 电影模块路由 }
# @Date: 2024/06/28 11:48
from fastapi import APIRouter
from handlers import MovieHandler
movie_router = APIRouter()
movie_router.add_api_route(
"/api/v1/movies", MovieHandler.get_movies, methods=["GET"], summary="获取电影列表"
)
movie_router.add_api_route(
"/api/v1/movies/{movie_id}", MovieHandler.get_movie_detail, methods=["GET"], summary="电影详情"
)
不同模块各自组织路由,就是通过 APIRouter 的 add_api_route 方法来添加路由信息,常用参数如下
-
path
路由路径 -
endpoint
对应路由处理函数 -
methods
路由请求方法列表 -
response_model
响应数据模型(pydantic的model) -
summary
路由备注 -
...
这里为了方便如何组织模块路由,一些请求模型、响应模型入参没有指定。
然后再 routers
下的 __init__
模块将各模块路由串联起来
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: __init__.py.py
# @Desc: { 项目路由初始化模块 }
# @Date: 2024/06/28 11:47
from fastapi import APIRouter
from .book import book_router
from .user import user_router
from .movie import movie_router
api_router = APIRouter()
api_router.include_router(user_router, tags=["用户模块"])
api_router.include_router(book_router, tags=["图书模块"])
api_router.include_router(movie_router, tags=["电影模块"])
使用 APIRouter 的 include_router 方法进行套娃串联路由,可以指定一些路由前缀、路由模块tags标记等信息,我一开始写项目的喜欢指定一些路由前缀 /api/v1
、/users
等,这样在写代码的时候可以少写,但实际使用上我抓包获取的接口路由发现定位代码的时候不方便,因为路由路径是组合到一起的,全局搜不到,就不能快速定位,于是还是取消了前缀。如下就是指定前缀的方式
python
复制代码
api_router = APIRouter(prefix="/api/v1")
api_router.include_router(user_router, prefix="/users", tags=["用户模块"])
api_router.include_router(book_router, prefix="/books", tags=["图书模块"])
api_router.include_router(movie_router, prefix="/movies", tags=["电影模块"])
路由处理模块
图书模块handler
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: book.py
# @Desc: { 图书模块handler }
# @Date: 2024/06/28 11:58
class BookHandler:
@classmethod
async def get_books(cls, book_name: str):
"""获取图书列表"""
# 参数校验
# 调用业务层处理
# 响应出参
return "获取图书列表"
@classmethod
async def get_book_detail(cls, book_id: int):
return "获取图书详情"
电影模块handler
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: movie.py
# @Desc: { 电影模块handler }
# @Date: 2024/06/28 11:58
class MovieHandler:
@classmethod
async def get_movies(cls, movie_name: str, movie_type: str):
"""获取电影列表"""
# 参数校验
# 调用业务层处理
# 响应出参
return "获取电影列表"
@classmethod
async def get_movie_detail(cls, movie_id: int):
return "获取电影详情"
用户模块handler
python
复制代码
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @File: user.py
# @Desc: { 用户模块handler }
# @Date: 2024/06/28 11:58
class UserHandler:
@classmethod
async def register(cls, username: str, password: str):
return "用户注册"
@classmethod
async def login(cls, username: str, password: str):
return "用户登录"
@classmethod
async def get_user_detail(cls, user_id: int):
return "获取用户详情"
@classmethod
async def get_users(cls, username: str):
"""获取用户列表"""
# 参数校验
# 调用业务层处理
# 响应出参
return "获取用户列表"
handler 其实就是路由视图函数,这层的作用主要就是进行如下处理
- 参数校验
- 调用业务层(service)处理
- 响应出参
路由API展示
直接访问 http://127.0.0.1:8000/docs#/
就可以查看路由接口文档
fastapi还是很方便的将代码路由结构组织好了,api接口文档也生成了,如果在线的接口文档用的不方便可以直接导入到APIFOX 中是使用。
感兴趣可以查看这篇文章:与go比肩的FastAPI,如何快速入门
源代码
Github:FastAPI 实战手册
从FastAPI的安装、请求处理、响应返回等基础知识入手,到中间件、数据库操作、身份认证等核心组件的应用,再到实战项目的开发,以及源码分析,循序渐进地介绍FastAPI的使用,旨在让读者全面掌握这个框架。
源文:FastAPI 工程化模块路由 - APIRouter
如有侵权请联系站点删除!
技术合作服务热线,欢迎来电咨询!