Example #1
0
    def init_app(self, app):
        self.app = app
        self.spec = self.app.config.get('APISPEC_SPEC') or \
                    make_apispec(self.app.config.get('APISPEC_TITLE', 'flask-apispec'),
                                 self.app.config.get('APISPEC_VERSION', 'v1'))
        self.add_swagger_routes()
        self.resource_converter = ResourceConverter(self.app, spec=self.spec)
        self.view_converter = ViewConverter(app=self.app, spec=self.spec)

        for deferred in self._deferred:
            deferred()
Example #2
0
def test_error_if_spec_does_not_have_marshmallow_plugin(app):
    bad_spec = APISpec(
        title='title',
        version='v1',
        plugins=[],  # oh no! no MarshmallowPlugin
    )
    with pytest.raises(RuntimeError):
        ViewConverter(app=app, spec=bad_spec)
    with pytest.raises(RuntimeError):
        ResourceConverter(app=app, spec=bad_spec)
Example #3
0
    def init_app(self):
        """Override base init_app method."""
        self.view_converter = ViewConverter(self.app)
        self.resource_converter = ResourceConverter(self.app)
        self.spec = APISpec(title=self.title,
                            version=self.version,
                            info={'description': self.top_level_description},
                            plugins=['apispec.ext.marshmallow'])

        self.add_swagger_routes()

        for deferred in self._deferred:
            deferred()
Example #4
0
    def init_app(self, **kwargs):
        """
        Override base init_app method.

        :param kwargs: args
        """
        self.spec = APISpec(title=self.title,
                            version=self.version,
                            info={'description': self.top_level_description},
                            plugins=[MarshmallowPlugin()],
                            openapi_version='2.0')

        self.resource_converter = ResourceConverter(self.app, self.spec)
        self.view_converter = ViewConverter(self.app, self.spec)
        self.add_swagger_routes()

        for deferred in self._deferred:
            deferred()
Example #5
0
class FlaskApiSpec(object):
    """Flask-apispec extension.

    Usage:

    .. code-block:: python

        app = Flask(__name__)
        app.config.update({
            'APISPEC_SPEC': APISpec(
                title='pets',
                version='v1',
                openapi_version='2.0',
                plugins=[MarshmallowPlugin()],
            ),
            'APISPEC_SWAGGER_URL': '/swagger/',
        })
        docs = FlaskApiSpec(app)

        @app.route('/pet/<pet_id>')
        def get_pet(pet_id):
            return Pet.query.filter(Pet.id == pet_id).one()

        docs.register(get_pet)

    :param Flask app: App associated with API documentation
    :param APISpec spec: apispec specification associated with API documentation
    """
    def __init__(self,
                 app=None,
                 static_folder='./static',
                 template_folder='./templates',
                 static_url_path='/flask-apispec/static'):
        self._deferred = []
        self.app = app
        self.view_converter = None
        self.resource_converter = None
        self.spec = None
        self.static_folder = static_folder
        self.template_folder = template_folder
        self.static_url_path = static_url_path

        if app:
            self.init_app(app)

    def init_app(self, app):
        self.app = app
        self.spec = self.app.config.get('APISPEC_SPEC') or \
                    make_apispec(self.app.config.get('APISPEC_TITLE', 'flask-apispec'),
                                 self.app.config.get('APISPEC_VERSION', 'v1'),
                                 self.app.config.get('APISPEC_OAS_VERSION', '2.0'))
        self.add_swagger_routes()
        self.resource_converter = ResourceConverter(self.app, spec=self.spec)
        self.view_converter = ViewConverter(app=self.app, spec=self.spec)

        for deferred in self._deferred:
            deferred()

    def _defer(self, callable, *args, **kwargs):
        bound = functools.partial(callable, *args, **kwargs)
        self._deferred.append(bound)
        if self.app:
            bound()

    def add_swagger_routes(self):
        blueprint = flask.Blueprint(
            'flask-apispec',
            __name__,
            static_folder=self.static_folder,
            template_folder=self.template_folder,
            static_url_path=self.static_url_path,
        )

        json_url = self.app.config.get('APISPEC_SWAGGER_URL', '/swagger/')
        if json_url:
            blueprint.add_url_rule(json_url, 'swagger-json', self.swagger_json)

        ui_url = self.app.config.get('APISPEC_SWAGGER_UI_URL', '/swagger-ui/')
        if ui_url:
            blueprint.add_url_rule(ui_url, 'swagger-ui', self.swagger_ui)

        self.app.register_blueprint(blueprint)

    def swagger_json(self):
        return flask.jsonify(self.spec.to_dict())

    def swagger_ui(self):
        return flask.render_template('swagger-ui.html')

    def register_existing_resources(self):
        for name, rule in self.app.view_functions.items():
            try:
                blueprint_name, _ = name.split('.')
            except ValueError:
                blueprint_name = None

            try:
                self.register(rule, blueprint=blueprint_name)
            except TypeError:
                pass

    def register(self,
                 target,
                 endpoint=None,
                 blueprint=None,
                 resource_class_args=None,
                 resource_class_kwargs=None,
                 custom_path=None):
        """Register a view.

        :param custom_path: (optional) Override the path property for the endpoint
        :param target: view function or view class.
        :param endpoint: (optional) endpoint name.
        :param blueprint: (optional) blueprint name.
        :param tuple resource_class_args: (optional) args to be forwarded to the
            view class constructor.
        :param dict resource_class_kwargs: (optional) kwargs to be forwarded to
            the view class constructor.
        """

        self._defer(self._register, target, endpoint, blueprint,
                    resource_class_args, resource_class_kwargs, custom_path)

    def _register(self,
                  target,
                  endpoint=None,
                  blueprint=None,
                  resource_class_args=None,
                  resource_class_kwargs=None,
                  custom_path=None):
        """Register a view.

        :param target: view function or view class.
        :param endpoint: (optional) endpoint name.
        :param blueprint: (optional) blueprint name.
        :param tuple resource_class_args: (optional) args to be forwarded to the
            view class constructor.
        :param dict resource_class_kwargs: (optional) kwargs to be forwarded to
            the view class constructor.
        """
        if isinstance(target, types.FunctionType):
            paths = self.view_converter.convert(target, endpoint, blueprint)
        elif isinstance(target, ResourceMeta):
            paths = self.resource_converter.convert(
                target,
                endpoint,
                blueprint,
                resource_class_args=resource_class_args,
                resource_class_kwargs=resource_class_kwargs,
            )
        else:
            raise TypeError()

        if custom_path and len(paths) == 1:
            path = paths[0]
            path['path'] = rule_path_to_path(custom_path)
            self.spec.path(**path)
        else:
            for path in paths:
                self.spec.path(**path)
Example #6
0
 def path(self, app, spec, function_view):
     converter = ViewConverter(app)
     paths = converter.convert(function_view)
     for path in paths:
         spec.add_path(**path)
     return spec._paths['/bands/{band_id}/']
Example #7
0
 def __init__(self, app):
     self.app = app
     self.view_converter = ViewConverter(self.app)
     self.resource_converter = ResourceConverter(self.app)
     self.spec = self.app.config.get('APISPEC_SPEC') or make_apispec()
     self.add_routes()
Example #8
0
class FlaskApiSpec(object):
    """Flask-apispec extension.

    Usage:

    .. code-block:: python

        app = Flask(__name__)
        app.config.update({
            'APISPEC_SPEC': APISpec(
                title='pets',
                version='v1',
                plugins=['apispec.ext.marshmallow'],
            ),
            'APISPEC_SWAGGER_URL': '/swagger/',
        })
        docs = FlaskApiSpec(app)

        @app.route('/pet/<pet_id>')
        def get_pet(pet_id):
            return Pet.query.filter(Pet.id == pet_id).one()

        docs.register(get_pet)

    :param Flask app: App associated with API documentation
    :param APISpec spec: apispec specification associated with API documentation
    """
    def __init__(self, app):
        self.app = app
        self.view_converter = ViewConverter(self.app)
        self.resource_converter = ResourceConverter(self.app)
        self.spec = self.app.config.get('APISPEC_SPEC') or make_apispec()
        self.add_routes()

    def add_routes(self):
        blueprint = flask.Blueprint(
            'flask-apispec',
            __name__,
            static_folder='./static',
            template_folder='./templates',
            static_url_path='/flask-apispec/static',
        )

        json_url = self.app.config.get('APISPEC_SWAGGER_URL', '/swagger/')
        if json_url:
            blueprint.add_url_rule(json_url, 'swagger-json', self.swagger_json)

        ui_url = self.app.config.get('APISPEC_SWAGGER_UI_URL', '/swagger-ui/')
        if ui_url:
            blueprint.add_url_rule(ui_url, 'swagger-ui', self.swagger_ui)

        self.app.register_blueprint(blueprint)

    def swagger_json(self):
        return flask.jsonify(self.spec.to_dict())

    def swagger_ui(self):
        return flask.render_template('swagger-ui.html')

    def register(self,
                 target,
                 endpoint=None,
                 blueprint=None,
                 resource_class_args=None,
                 resource_class_kwargs=None):
        """Register a view.

        :param target: view function or view class.
        :param endpoint: (optional) endpoint name.
        :param blueprint: (optional) blueprint name.
        :param tuple resource_class_args: (optional) args to be forwarded to the
            view class constructor.
        :param dict resource_class_kwargs: (optional) kwargs to be forwarded to
            the view class constructor.
        """
        if isinstance(target, types.FunctionType):
            paths = self.view_converter.convert(target, endpoint, blueprint)
        elif isinstance(target, ResourceMeta):
            paths = self.resource_converter.convert(
                target,
                endpoint,
                blueprint,
                resource_class_args=resource_class_args,
                resource_class_kwargs=resource_class_kwargs,
            )
        else:
            raise TypeError()
        for path in paths:
            self.spec.add_path(**path)
Example #9
0
 def path(self, app, spec_oapi3, function_view):
     converter = ViewConverter(app=app, spec=spec_oapi3)
     paths = converter.convert(function_view)
     for path in paths:
         spec_oapi3.path(**path)
     return spec_oapi3._paths['/bands/{band_id}/']