From 2cab5310c93b19f0ef918cb54c5b233ed0b5dd03 Mon Sep 17 00:00:00 2001 From: Gardient Date: Tue, 21 Sep 2021 19:51:23 +0300 Subject: [PATCH] add apispec swagger generation --- api/__init__.py | 32 +++++++++++++++++++++++++++++--- api/extensions.py | 2 ++ api/login/views.py | 1 - 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/api/__init__.py b/api/__init__.py index e52c7ff..e7eb19b 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -1,7 +1,7 @@ from flask import Flask, Blueprint from . import commands, login, target_exchange from .settings import ProdConfig, Config -from .extensions import db, migrate, jwt +from .extensions import db, migrate, jwt, apispec from .exceptions import ApiException @@ -16,6 +16,7 @@ def create_app(config: Config = ProdConfig) -> Flask: app.config.from_object(config) register_extensions(app) register_blueprints(app) + register_apispecs(app) register_errorhandlers(app) register_shellcontext(app) register_commands(app) @@ -28,18 +29,43 @@ def register_extensions(app: Flask): db.init_app(app) migrate.init_app(app, db) jwt.init_app(app) + apispec.init_app(app) def register_blueprints(app: Flask): """Register Flask blueprints.""" api_blueprint = Blueprint('api', __name__, url_prefix='/api') - api_blueprint.register_blueprint(login.views.blueprint, url_prefix='/login') - api_blueprint.register_blueprint(target_exchange.views.blueprint, url_prefix='/target-exchange') + api_blueprint.register_blueprint( + login.views.blueprint, url_prefix='/login') + api_blueprint.register_blueprint( + target_exchange.views.blueprint, url_prefix='/target-exchange') app.register_blueprint(api_blueprint) +def register_apispecs(app: Flask): + """Register routes for apispec + + Extended from FlaskApiSpec::register_existing_resources + that one doesn't handle the static routes or blueprints in blueprints well + """ + + for name, rule in app.view_functions.items(): + if name == 'static': + continue + + try: + blueprint_name, _ = name.rsplit('.', 1) + except ValueError: + blueprint_name = None + + try: + apispec.register(rule, blueprint=blueprint_name) + except TypeError: + pass + + def register_errorhandlers(app: Flask): def errorHandler(error: ApiException): return error.to_response() diff --git a/api/extensions.py b/api/extensions.py index b858d81..e07de38 100644 --- a/api/extensions.py +++ b/api/extensions.py @@ -1,6 +1,7 @@ from flask_jwt_extended import JWTManager from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy, Model +from flask_apispec import FlaskApiSpec class CRUDMixin(Model): """Mixin that adds convenience methods for CRUD (create, read, update, delete) operations.""" @@ -32,3 +33,4 @@ class CRUDMixin(Model): db = SQLAlchemy(model_class=CRUDMixin) migrate = Migrate() jwt = JWTManager() +apispec = FlaskApiSpec() diff --git a/api/login/views.py b/api/login/views.py index 536a6bc..042baed 100644 --- a/api/login/views.py +++ b/api/login/views.py @@ -16,7 +16,6 @@ blueprint = Blueprint('login', __name__) @use_kwargs(login_schema) @marshal_with(token_response_schema) def login_user(username, password, **kwargs): - print(f'user: {username}; pass: {password}; expected:{current_app.config[constants.API_PASS]}') if username == constants.API_USER and password == current_app.config[constants.API_PASS]: return TokenResponse(create_access_token(identity=username, fresh=True)) else: