Beispiel #1
0
    def __init__(self, app, *, plugins=None):
        self.app = app

        plugins = plugins and list(plugins) or []
        self.flask_plugin = FlaskPlugin()
        self.ma_plugin = MarshmallowPlugin()
        plugins.extend([self.flask_plugin, self.ma_plugin])

        super().__init__(title=app.config.API_TITLE or app.name,
                         version=app.config.API_VERSION,
                         openapi_version=app.config.API_OPENAPI_VERSION,
                         info=dict(description=app.config.API_DESCRIPTION),
                         plugins=plugins)
        self.register_routes(app)
Beispiel #2
0
    def path_helper(self, path, view, **kwargs):
        """Path helper for Flask-RESTy views.

        :param view: An `ApiView` object.
        """
        super(FlaskRestyPlugin, self).path_helper(path=path,
                                                  view=view,
                                                  **kwargs)

        resource = self.get_state().views[view]
        rule = self._rules[resource.rule]

        operations = defaultdict(Operation)
        view_instance = view()
        view_instance.spec_declaration(view, operations, self)

        # add path arguments
        parameters = []
        for arg in rule.arguments:
            parameters.append({
                'name': arg,
                'in': 'path',
                'required': True,
                'type': 'string',
            })
        if parameters:
            operations['parameters'] = parameters

        path.path = FlaskPlugin.flaskpath2openapi(resource.rule)
        path.operations = dict(**operations)
Beispiel #3
0
def spec(request):
    return APISpec(
        title='Swagger Petstore',
        version='1.0.0',
        description='This is a sample Petstore server.  You can find out more '
        'about Swagger at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> '
        'or on irc.freenode.net, #swagger.  For this sample, you can use the api '
        'key \"special-key\" to test the authorization filters',
        plugins=(FlaskPlugin(), ),
    )
Beispiel #4
0
def spec(request):
    return APISpec(
        title='Swagger Petstore',
        version='1.0.0',
        description='This is a sample Petstore server.  You can find out more '
        'about Swagger at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> '
        'or on irc.freenode.net, #swagger.  For this sample, you can use the api '
        'key \"special-key\" to test the authorization filters',
        plugins=[
            # Test both plugin class and deprecated interface
            FlaskPlugin() if request.param else 'apispec.ext.flask',
        ],
    )
Beispiel #5
0
    def __init__(self, app=None, title='Sample API', version='0.1.0'):
        self._spec = APISpec(title=title,
                             version=version,
                             openapi_version='2.0',
                             plugins=(FlaskPlugin(), MarshmallowPlugin()))
        self._routes = {}
        self._schemas = {}

        self.app = None
        self.blueprint = None

        if app is not None:
            self.app = app
            self.init_app(app)
Beispiel #6
0
DAO.create({'name': 'remi'})
DAO.create({'name': 'caro'})

app = Flask(__name__)
CORS(app)
"""
### flask + marshmallow + apispec implementation
"""

# Create an APISpec
spec = APISpec(
    title='MA Swagger UserAPI',
    version='1.0.0',
    openapi_version='2.0',
    plugins=(
        FlaskPlugin(),
        MarshmallowPlugin(),
    ),
)


class UserSchema(Schema):
    id = ma_fields.Integer()
    name = ma_fields.String()


class UserListResource(MethodView):
    def get(self):
        """User list
        ---
        responses:
Beispiel #7
0
class APISpec(apispec.APISpec):
    def __init__(self, app, *, plugins=None):
        self.app = app

        plugins = plugins and list(plugins) or []
        self.flask_plugin = FlaskPlugin()
        self.ma_plugin = MarshmallowPlugin()
        plugins.extend([self.flask_plugin, self.ma_plugin])

        super().__init__(title=app.config.API_TITLE or app.name,
                         version=app.config.API_VERSION,
                         openapi_version=app.config.API_OPENAPI_VERSION,
                         info=dict(description=app.config.API_DESCRIPTION),
                         plugins=plugins)
        self.register_routes(app)

    # FIXME make a controller for these routes, inject this extension into it
    def register_routes(self, app: FlaskUnchained):
        bp = Blueprint('api-docs',
                       __name__,
                       url_prefix=app.config.API_REDOC_URL_PREFIX.rstrip('/'),
                       template_folder=os.path.join(
                           os.path.dirname(os.path.abspath(__file__)),
                           'templates'))

        # Serve json spec at `API_REDOC_URL_PREFIX/openapi.json` by default
        bp.add_url_rule(app.config.API_OPENAPI_JSON_PATH,
                        endpoint='openapi_json',
                        view_func=self._openapi_json)

        # Serve ReDoc at `API_REDOC_URL_PREFIX/` by default
        bp.add_url_rule(app.config.API_REDOC_PATH,
                        endpoint='openapi_redoc',
                        view_func=self._openapi_redoc)

        app.register_blueprint(bp, register_with_babel=False)

    def _openapi_json(self):
        """Serve JSON spec file"""
        # We don't use Flask.jsonify here as it would sort the keys
        # alphabetically while we want to preserve the order.
        from pprint import pprint
        pprint(self.to_dict())
        return current_app.response_class(json.dumps(self.to_dict(), indent=4),
                                          mimetype='application/json')

    def _openapi_redoc(self):
        """
        Expose OpenAPI spec with ReDoc

        The ReDoc script URL can be specified as ``API_REDOC_SOURCE_URL``
        """
        return render_template('openapi/redoc.html',
                               title=self.app.config.API_TITLE
                               or self.app.name,
                               redoc_url=self.app.config.API_REDOC_SOURCE_URL)

    def register_converter(self, converter, conv_type, conv_format=None):
        """
        Register custom path parameter converter

        :param BaseConverter converter: Converter.
            Subclass of werkzeug's BaseConverter
        :param str conv_type: Parameter type
        :param str conv_format: Parameter format (optional)
        """
        self.flask_plugin.register_converter(converter, conv_type, conv_format)

    def register_field(self, field, *args):
        """
        Register custom Marshmallow field

        Registering the Field class allows the Schema parser to set the proper
        type and format when documenting parameters from Schema fields.
        :param Field field: Marshmallow Field class
        ``*args`` can be:
        - a pair of the form ``(type, format)`` to map to
        - a core marshmallow field type (then that type's mapping is used)
        """
        self.ma_plugin.map_to_openapi_type(*args)(field)
Beispiel #8
0
    data = {'status': 'ok'}

    return jsonify(StatusResponse().dump(data).data)


if __name__ == '__main__':
    import json

    from apispec import APISpec
    from apispec.ext.flask import FlaskPlugin
    from apispec.ext.marshmallow import MarshmallowPlugin

    spec = APISpec(title='Flask project',
                   version='v1',
                   openapi_version='2.0',
                   host='example.com',
                   basePath='/api',
                   schemes=['https'],
                   consumes=['application/json'],
                   produces=['application/json'],
                   plugins=[FlaskPlugin(), MarshmallowPlugin()])

    spec.definition('StatusResponse', schema=StatusResponse)

    with app.test_request_context():
        spec.add_path(view=api_status)

    spec = spec.to_dict()

    print(json.dumps(spec, indent=2))
Beispiel #9
0
class APISpec(apispec.APISpec):
    def __init__(self, app, *, plugins=None):
        self.app = app

        plugins = plugins and list(plugins) or []
        self.flask_plugin = FlaskPlugin()
        self.ma_plugin = MarshmallowPlugin()
        plugins.extend([self.flask_plugin, self.ma_plugin])

        super().__init__(
            title=app.config.get('API_TITLE', app.name),
            version=app.config.get('API_VERSION', '1'),
            openapi_version=app.config.get('API_OPENAPI_VERSION', '2.0'),
            info=dict(description=app.config.get('API_DESCRIPTION', None), ),
            plugins=plugins,
        )
        self.register_routes(app)

    def register_routes(self, app: FlaskUnchained):
        redoc_url_prefix = app.config.get('API_REDOC_URL_PREFIX',
                                          '/api-docs').rstrip('/')
        template_folder = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'templates')
        bp = Blueprint('api-docs',
                       __name__,
                       url_prefix=redoc_url_prefix,
                       template_folder=template_folder)

        # Serve json spec at 'url_prefix/openapi.json' by default
        json_path = app.config.get('OPENAPI_JSON_PATH', 'openapi.json')
        bp.add_url_rule(json_path,
                        endpoint='openapi_json',
                        view_func=self._openapi_json)

        # Serve ReDoc at `url_prefix/' by default
        redoc_path = app.config.get('OPENAPI_REDOC_PATH', '/')
        bp.add_url_rule(redoc_path,
                        endpoint='openapi_redoc',
                        view_func=self._openapi_redoc)

        app.register_blueprint(bp, register_with_babel=False)

    def _openapi_json(self):
        """Serve JSON spec file"""
        # We don't use Flask.jsonify here as it would sort the keys
        # alphabetically while we want to preserve the order.
        from pprint import pprint
        pprint(self.to_dict())
        return current_app.response_class(json.dumps(self.to_dict(), indent=4),
                                          mimetype='application/json')

    def _openapi_redoc(self):
        """
        Expose OpenAPI spec with ReDoc

        The ReDoc script URL can be specified as OPENAPI_REDOC_URL.
        Otherwise, a CDN script is used based on the ReDoc version. The
        version can - and should - be specified as OPENAPI_REDOC_VERSION,
        otherwise, 'latest' is used.
        When using 1.x branch (i.e. when OPENAPI_REDOC_VERSION is "latest" or
        begins with "v1"), GitHub CDN is used.
        When using 2.x branch (i.e. when OPENAPI_REDOC_VERSION is "next" or
        begins with "2" or "v2"), unpkg nmp CDN is used.
        OPENAPI_REDOC_VERSION is ignored when OPENAPI_REDOC_URL is passed.
        """
        redoc_url = self.app.config.get('OPENAPI_REDOC_URL', None)
        redoc_version = self.app.config.get('OPENAPI_REDOC_VERSION', 'next')
        if redoc_url is None:
            redoc_url = (
                'https://cdn.jsdelivr.net/npm/redoc@'
                '{}/bundles/redoc.standalone.js'.format(redoc_version))
        return render_template('redoc.html',
                               title=self.app.config.get(
                                   'API_TITLE', self.app.name),
                               redoc_url=redoc_url)

    def register_converter(self, converter, conv_type, conv_format=None):
        """
        Register custom path parameter converter

        :param BaseConverter converter: Converter.
            Subclass of werkzeug's BaseConverter
        :param str conv_type: Parameter type
        :param str conv_format: Parameter format (optional)
        """
        self.flask_plugin.register_converter(converter, conv_type, conv_format)

    def register_field(self, field, *args):
        """
        Register custom Marshmallow field

        Registering the Field class allows the Schema parser to set the proper
        type and format when documenting parameters from Schema fields.
        :param Field field: Marshmallow Field class
        ``*args`` can be:
        - a pair of the form ``(type, format)`` to map to
        - a core marshmallow field type (then that type's mapping is used)
        """
        self.ma_plugin.map_to_openapi_type(*args)(field)