Flask 搭建 Restful 风格项目扩展(Namespace、Swagger)

这里主要是对之前搭建的一个 Flask Restful 代码库(Flask 搭建 Restful 风格项目扩展)进行一个小的改进,主要包括以下方面

  1. 为接口自动生成 swagger 使用文档
  2. 使用 Namespace 管理 API 接口
  3. 为项目添加适配 lingma IDE 的项目提示词

最终项目目录

markdown 复制代码
.
├── app
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   ├── common
│   │   │   └── utils.py
│   │   ├── models
│   │   │   ├── __init__.py
│   │   │   ├── revoked_token.py
│   │   │   └── user.py
│   │   ├── resources
│   │   │   ├── __init__.py
│   │   │   ├── auth
│   │   │   │   ├── __init__.py
│   │   │   │   ├── auth_api_model.py
│   │   │   │   ├── login.py
│   │   │   │   ├── logout.py
│   │   │   │   └── register.py
│   │   │   └── user
│   │   │       ├── __init__.py
│   │   │       ├── user_api_model.py
│   │   │       └── user.py
│   │   └── schema
│   │       └── register_sha.py
│   ├── config.py
│   └── manage.py
├── LICENSE
├── README.md
├── requirements.txt
└── run.py

需要完成以上优化,首先我们需要将 Flask-RESTful 更改为 flask-restx

pip install flask-restx==1.3.0,版本可按需更改

使用 Namespace 管理 API 接口

  1. 引入 flask_restx中的 Namespace
  2. 创建我们需要的 Namespace 对象
  3. 通过 Namespace 对象来添加 Resource

未使用 Namespace

python 复制代码
# app/api/__init__.py
from flask import Blueprint
from flask_restful import Api
from .resources.register import Register
from .resources.login import Login
from .resources.logout import Logout
from .resources.user import UserService

api_blueprint = Blueprint('api', __name__, url_prefix='/api')
api = Api(api_blueprint)

api.add_resource(Register, '/register')
api.add_resource(Login, '/login')
# api.add_resource(Login, '/login', '/refresh', '/test')  # 可以添加多个路由

api.add_resource(Logout, '/logout')
api.add_resource(UserService, '/user')

使用 Namespace

python 复制代码
# app/api/__init__.py
from flask import Blueprint
from flask_restx import Api, Namespace

# 创建API蓝图
api_blueprint = Blueprint('api', __name__, url_prefix='/api')

# 创建Flask-RESTX的Api实例
api = Api(
    api_blueprint,
    version='1.0',
    title='Flask RESTful API',
    description='基于Flask-RESTX的RESTful API',
    doc='/docs/',  # Swagger文档路径
    authorizations={
        'Bearer': {
            'type': 'apiKey',
            'in': 'header',
            'name': 'Authorization',
            'description': 'JWT Token格式: Bearer <token>'
        }
    },
    security='Bearer'
)

auth_ns = Namespace('auth', description='认证相关接口', path='/auth')
users_ns = Namespace('users', description='用户管理接口', path='/users')

from app.api.resources.auth.login import Login
from app.api.resources.auth.logout import Logout
from app.api.resources.auth.register import Register
from app.api.resources.user.user import UserService

auth_ns.add_resource(Register, '/register')
auth_ns.add_resource(Login, '/login')
auth_ns.add_resource(Logout, '/logout')

users_ns.add_resource(UserService, '/profile')
# 注册命名空间到API
api.add_namespace(auth_ns)
api.add_namespace(users_ns)

对于以上代码,需要注意:

如果我们将 Namespace 的定义放到导入语句之后,如下所示:

python 复制代码
from app.api.resources.auth.login
import Login from app.api.resources.auth.logout
import Logout from app.api.resources.auth.register
import Register from app.api.resources.user.user
import UserService
auth_ns = Namespace('auth', description='认证相关接口', path='/auth')
users_ns = Namespace('users', description='用户管理接口', path='/users')
  1. 导入模块中引用 auth_ns 会导致错误:
    • LoginLogout 等类所在的模块中使用了 auth_ns(例如注册资源 @auth_ns.route()),而 auth_ns 在导入之后才定义,那么会抛出 NameError,因为此时 auth_ns 还未定义。
  2. 循环引用风险:
    • 如果 Login 类所在的模块又导入了 app.api.__init__ 中的某些内容(如 auth_ns),就可能形成循环依赖(A 导入 B,B 又导入 A)。

为接口自动生成 swagger 使用文档

  1. 请求与响应模型的定义声明
python 复制代码
from app.api import auth_ns
from flask_restx import fields
# from app.api.common.utils import api_response
# 定义API模型
# 用户注册/登录请求模型
user_credentials = auth_ns.model('UserCredentials', {
    'username': fields.String(required=True, description='用户名', example='admin'),
    'password': fields.String(required=True, description='密码', example='admin')
})

# 用户注册/登录响应模型

# 登录成功响应模型
login_response_data = auth_ns.model('LoginResponseData', {
    'access_token': fields.String(description='访问令牌'),
    'refresh_token': fields.String(description='刷新令牌'),
    'exp': fields.Integer(description='令牌过期时间戳(毫秒)')
})

login_response = auth_ns.model('LoginResponse', {
    'success': fields.Boolean(description='操作是否成功'),
    'message': fields.String(description='响应消息'),
    'data': fields.Nested(login_response_data, description='登录响应数据')
})

# 登录响应模型(继承api_response)
# login_response = auth_ns.inherit('LoginResponse', api_response, {
#     'data': fields.Nested(login_response_data, description='登录响应数据')
# })

# 使用 clone 方法复制 api_response,并修改 data 字段
# login_response = auth_ns.clone('LoginResponse', api_response, {
#     'data': fields.Nested(login_response_data, description='登录响应数据')
# })
# login_response = auth_ns.clone('LoginResponse', api_response)
# login_response['data'] = fields.Nested(login_response_data, description='登录响应数据')

注意:

auth_ns.inherit这个是想实现一个类似于面向对象编程中的 class 继承效果的,考虑到可能会有一些通用响应的对象格式,比如

python 复制代码
api_response = api.model('ApiResponse', {
    'success': fields.Boolean(description='操作是否成功'),
    'message': fields.String(description='响应消息'),
    # 'data': fields.Raw(description='响应数据'),
    # 'code': fields.Integer(description='响应状态码')
})

auth_ns.inherit使用时不能重写 qpi_response 中的属性,可以使用 auth_ns.clone来实现

python 复制代码
# 使用 clone 方法复制 api_response,并修改 data 字段
login_response = auth_ns.clone('LoginResponse', api_response, {
    'data': fields.Nested(login_response_data, description='登录响应数据')
})
# login_response = auth_ns.clone('LoginResponse', api_response)
# login_response['data'] = fields.Nested(login_response_data, description='登录响应数据')
  1. 接口注解添加

@auth_ns.expect(user_credentials)

  • 指定该接口期望的输入参数格式。这里的 user_credentials 是一个定义好的请求参数模型,通常包含用户名和密码等字段。
  • 在生成的 Swagger 文档中,会显示该接口需要的请求体格式,并进行参数校验。

@auth_ns.marshal_with(login_response)

  • 指定该接口返回的数据格式。login_response 是一个定义好的响应模型,通常包含登录成功后的用户信息和 Token。
  • 确保返回给客户端的数据结构一致,并且可以根据需求选择性地返回部分字段。

@auth_ns.doc(description='用户登录接口', responses={...})

  • 为该接口添加详细的文档描述和响应码说明。
  • description:提供接口的功能描述,帮助开发者理解该接口的作用。
  • responses:定义不同 HTTP 状态码对应的响应描述,例如 200 表示登录成功,400 表示用户不存在等。
  • 在 Swagger UI 中展示更详细的接口文档,方便测试和使用。
python 复制代码
# ...
from app.api import auth_ns
from .auth_api_model import user_credentials, login_response

class Login(Resource):
    @auth_ns.expect(user_credentials)
    @auth_ns.marshal_with(login_response)
    @auth_ns.doc(description='用户登录接口',
             responses={
                 200: '登录成功',
                 400: '用户不存在',
                 401: '密码错误',
                 500: '服务器内部错误'
             })
    def post(self):
	    pass

    @jwt_required(refresh=True)
    @auth_ns.doc(description='用户token 刷新接口',
             responses={
                 200: '登录成功',
                 500: '服务器内部错误'
             })
    @auth_ns.marshal_with(login_response)
    def get(self):
	    pass
  1. 测试

可以通过 http://127.0.0.1:5003/api/docs/ 本地查看 swagger 文档,并调试

为项目添加适配 lingma IDE 的项目提示词

规则 vscode 也适配

详细可参考 lingma规则设置

相关推荐
WanderInk1 小时前
深入解析:Java Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); 一行代码的背后功力
java·后端·算法
codeGoogle2 小时前
“ASIC项目90%会失败”,黄仁勋的“诅咒”劝退华为?
后端
追逐时光者2 小时前
一款基于 .NET 开源免费、轻量快速、跨平台的 PDF 阅读器
后端·.net
默默地离开3 小时前
前端开发中的 Mock 实践与接口联调技巧
前端·后端·设计模式
杨荧3 小时前
基于爬虫技术的电影数据可视化系统 Python+Django+Vue.js
开发语言·前端·vue.js·后端·爬虫·python·信息可视化
在雨季等你4 小时前
奋斗在创业路上的老开发
android·前端·后端
转转技术团队4 小时前
游戏账号大图生成
java·后端
程序员爱钓鱼4 小时前
Go语言实战案例-批量重命名文件
后端·google·go
大熊计算机4 小时前
大模型推理加速实战,vLLM 部署 Llama3 的量化与批处理优化指南
后端
程序员爱钓鱼4 小时前
Go语言实战案例-遍历目录下所有文件
后端·google·go