diff --git a/api/__init__.py b/api/__init__.py index b040f1d..7c6570a 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -53,6 +53,9 @@ def register_apispecs(app: Flask): that one doesn't handle the static routes or blueprints in blueprints well """ + apispec.spec.components.security_scheme('api_key', {"type": "apiKey", "in": "query", "name": "apikey"}) + apispec.spec.components.security_scheme('jwt', {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}) + for name, rule in app.view_functions.items(): if name == 'static': continue diff --git a/api/login/serializers.py b/api/login/serializers.py index 93cd625..047e447 100644 --- a/api/login/serializers.py +++ b/api/login/serializers.py @@ -1,11 +1,14 @@ from marshmallow import Schema, fields + class LoginSchema(Schema): - username = fields.Str() - password = fields.Str(load_only=True) + username = fields.Str(required=True) + password = fields.Str(required=True, load_only=True) + class TokenResponseSchema(Schema): token = fields.Str() + login_schema = LoginSchema() token_response_schema = TokenResponseSchema() diff --git a/api/login/views.py b/api/login/views.py index d5409e1..089446b 100644 --- a/api/login/views.py +++ b/api/login/views.py @@ -4,21 +4,19 @@ from flask_apispec import use_kwargs, marshal_with, doc from marshmallow import fields from api.exceptions import BadRequestException +from api.utils import docwrap import api.constants as constants -from .serializers import token_response_schema +from .serializers import token_response_schema, login_schema blueprint = Blueprint('login', __name__) -@doc(tags=['login']) +@docwrap('Login', None) @blueprint.route('', methods=['POST']) @jwt_required(optional=True) -@use_kwargs({ - 'username': fields.Str(required=True), - 'password': fields.Str(required=True) -}) +@use_kwargs(login_schema) @marshal_with(token_response_schema) -def login_user(username, password, **kwargs): +def login_user(username, password): if username == constants.API_USER and password == current_app.config[constants.API_PASS]: return {'token': create_access_token(identity=username, fresh=True, expires_delta=False)} else: diff --git a/api/registration/views.py b/api/registration/views.py index 792d94b..b8be25b 100644 --- a/api/registration/views.py +++ b/api/registration/views.py @@ -5,18 +5,21 @@ from marshmallow import fields from sqlalchemy import or_ from api.exceptions import NotFoundException, BadRequestException +from api.utils import docwrap from api.target.models import Target from api.target_exchange.models import TargetExchange + from .models import Registration from .serializers import registration_schema, registrations_schema blueprint = Blueprint('Registration', __name__) +doc = docwrap('Registration') -@doc(tags=['Registration']) +@doc @blueprint.route('', methods=['GET']) @jwt_required() -@use_kwargs({'exchange': fields.Str(), 'target': fields.Str()}) +@use_kwargs({'exchange': fields.Str(), 'target': fields.Str()}, location='query') @marshal_with(registrations_schema) def get_list(exchange=None, target=None): res = Registration.query @@ -26,7 +29,7 @@ def get_list(exchange=None, target=None): return res.all() -@doc(tags=['Registration']) +@doc @blueprint.route('', methods=['POST']) @jwt_required() @use_kwargs(registration_schema) @@ -43,7 +46,7 @@ def create(name, routing_key, targets): return registration -@doc(tags=['Registration']) +@doc @blueprint.route('/', methods=['GET']) @jwt_required() @marshal_with(registration_schema) @@ -55,7 +58,7 @@ def get_by_id(registration_id: int): return NotFoundException(Registration.__name__) -@doc(tags=['Registration']) +@doc @blueprint.route('/', methods=['PUT']) @jwt_required() @use_kwargs(registration_schema) diff --git a/api/settings.py b/api/settings.py index 423278a..962bfdf 100644 --- a/api/settings.py +++ b/api/settings.py @@ -18,6 +18,7 @@ class Config(object): JWT_AUTH_HEADER_PREFIX = 'Token' APISPEC_TITLE = 'MahssageBus API' APISPEC_VERSION = 'v0.1' + APISPEC_OAS_VERSION = '3.0.0' RABBITMQ_HOST = os.environ.get("RABBITMQ_HOST", "localhost") diff --git a/api/target/views.py b/api/target/views.py index daa8610..7e23ebb 100644 --- a/api/target/views.py +++ b/api/target/views.py @@ -5,16 +5,19 @@ from marshmallow import fields from api.exceptions import NotFoundException, BadRequestException from api.target_exchange.models import TargetExchange +from api.utils import docwrap + from .models import Target from .serializers import target_schema, targets_schema blueprint = Blueprint('target', __name__) +doc = docwrap('Target') -@doc(tags=['Target']) +@doc @blueprint.route('', methods=['GET']) @jwt_required() -@use_kwargs({'exchange': fields.Str()}) +@use_kwargs({'exchange': fields.Str()}, location='query') @marshal_with(targets_schema) def get_list(exchange=None): res = Target.query @@ -23,7 +26,7 @@ def get_list(exchange=None): return res.all() -@doc(tags=['Target']) +@doc @blueprint.route('', methods=['POST']) @jwt_required() @use_kwargs(target_schema) @@ -37,7 +40,7 @@ def create(name, routing_key, exchange): return target -@doc(tags=['Target']) +@doc @blueprint.route('/', methods=['GET']) @jwt_required() @marshal_with(target_schema) @@ -49,7 +52,7 @@ def get_by_id(target_id: int): return NotFoundException(Target.__name__) -@doc(tags=['Target']) +@doc @blueprint.route('/', methods=['PUT']) @jwt_required() @use_kwargs(target_schema) diff --git a/api/target_exchange/views.py b/api/target_exchange/views.py index 96b2484..cc75fb8 100644 --- a/api/target_exchange/views.py +++ b/api/target_exchange/views.py @@ -1,16 +1,18 @@ from flask import Blueprint from flask_jwt_extended import jwt_required -from flask_apispec import use_kwargs, marshal_with, doc +from flask_apispec import use_kwargs, marshal_with from api.exceptions import NotFoundException +from api.utils import docwrap from .models import TargetExchange from .serializers import target_exchange_schema, target_exchanges_schema blueprint = Blueprint('target_exchange', __name__) +doc = docwrap('TargetExchange') -@doc(tags=['TargetExchange']) +@doc @blueprint.route('', methods=['GET']) @jwt_required() @marshal_with(target_exchanges_schema) @@ -18,7 +20,7 @@ def get_list(): return TargetExchange.query.all() -@doc(tags=['TargetExchange']) +@doc @blueprint.route('', methods=['POST']) @jwt_required() @use_kwargs(target_exchange_schema) @@ -29,7 +31,7 @@ def create(name): return target_exchange -@doc(tags=['TargetExchange']) +@doc @blueprint.route('/', methods=['GET']) @jwt_required() @marshal_with(target_exchange_schema) @@ -41,7 +43,7 @@ def get_by_id(exchange_id): return NotFoundException(__name__) -@doc(tags=['TargetExchange']) +@doc @blueprint.route('/', methods=['PUT']) @jwt_required() @use_kwargs(target_exchange_schema) diff --git a/api/utils.py b/api/utils.py new file mode 100644 index 0000000..4626021 --- /dev/null +++ b/api/utils.py @@ -0,0 +1,5 @@ +from flask_apispec import doc + + +def docwrap(tag, security='jwt', **kwargs): + return doc(tags=[tag], security=([{security: []}] if security is not None else None), **kwargs)