OpServ-Monitoring/opserv-backend

View on GitHub
app/server/restful_api/flask_restful_wrapper.py

Summary

Maintainability
A
2 hrs
Test Coverage
from flask import request
from flask_basicauth import BasicAuth
from flask_restful import Api, Resource

from application_settings.app_settings import AppSettings
from .general.requestholder import RequestHolder
from .rest_api_management import RestApiManagement


class FlaskRestfulWrapper:
    __api = None

    # needed for basic authentication
    __basic_auth = None

    def __init__(self, app):
        self.__api = Api(app)

        # enable basic auth if a password is set
        password = AppSettings.get_setting(AppSettings.KEY_PASSWORD)
        if password is not None:
            app.config['BASIC_AUTH_USERNAME'] = 'opserv'
            app.config['BASIC_AUTH_PASSWORD'] = password

            self.__basic_auth = BasicAuth(app)

    def init_rest_api(self):
        endpoint_managements = RestApiManagement.get_endpoint_managements()

        for endpoint_management_tuple in endpoint_managements:
            self.__init_endpoints(*endpoint_management_tuple)

    def __init_endpoints(self, endpoints_prefix, endpoint_management, is_current=False):
        if endpoint_management is not None:
            version = endpoint_management.get_prefix()
            if version is None:
                version = ""

            endpoints = endpoint_management.get_endpoints()
            for endpoint in endpoints:
                self.__init_endpoint(endpoints_prefix, endpoint, version, is_current)

    def __init_endpoint(self, endpoints_prefix, endpoint_class, version, is_current):
        basic_auth = self.__basic_auth  # read basic_auth from wrapper class

        class CustomResource(Resource):
            if basic_auth is not None:
                # Enable basic auth for every http api endpoint
                method_decorators = [basic_auth.required]

            def get(self, **params):
                return self.__handle_request(**params)

            def post(self, **params):
                return self.__handle_request(**params)

            def put(self, **params):
                return self.__handle_request(**params)

            def delete(self, **params):
                return self.__handle_request(**params)

            def __handle_request(self, **params):
                request_holder = self.__get_request_holder(**params)

                endpoint = endpoint_class()
                response_holder = endpoint.handle_request(request_holder)

                return response_holder.get_body(), response_holder.get_status(), response_holder.get_response_headers()

            def __get_request_holder(self, **params):
                # the uri called to obtain this endpoint
                uri = request.url

                # http request method mapped accordingly to the RequestHolder definition
                http_method = self.__get_method_code(request.method)

                # data passed as http headers
                if http_method == RequestHolder.METHOD_GET():
                    headers = request.args
                elif http_method == RequestHolder.METHOD_POST() or http_method == RequestHolder.METHOD_PUT():
                    headers = request.form
                else:
                    headers = None

                body = request.get_json()

                return RequestHolder(uri, http_method, headers, params, body)

            @classmethod
            def __get_method_code(cls, method_string):
                if method_string == "GET":
                    return RequestHolder.METHOD_GET()

                if method_string == "POST":
                    return RequestHolder.METHOD_POST()

                if method_string == "PUT":
                    return RequestHolder.METHOD_PUT()

                if method_string == "DELETE":
                    return RequestHolder.METHOD_DELETE()

                return None

        resource = CustomResource()
        paths = self.__get_api_paths(endpoints_prefix, endpoint_class.get_paths(), version, is_current)
        endpoint_name = endpoints_prefix + version + endpoint_class.__name__

        self.__api.add_resource(resource, *paths, endpoint=endpoint_name)

    @classmethod
    def __get_api_paths(cls, base_api_path, sub_paths, version, is_current):
        paths = []

        for sub_path in sub_paths:
            paths.append(base_api_path + version + sub_path)

        if is_current:
            for sub_path in sub_paths:
                paths.append(base_api_path + "/current" + sub_path)

        return tuple(paths)


def init_rest_api(app):
    FlaskRestfulWrapper(app).init_rest_api()