FastAPI 工程化模块路由 - APIRouter

FastAPI 工程化模块路由 - APIRouter

技术博客 admin 160 浏览

前言

在构建中大型应用时,推荐使用 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

如有侵权请联系站点删除!

技术合作服务热线,欢迎来电咨询!