Search code examples
pythonflaskswaggeropenapiflask-restplus

Python Flask automatically generated Swagger/OpenAPI 3.0


Im trying to generate swagger document for my existing Flask app, I tried with Flask-RESTPlus initially and found out the project is abundant now and checked at the forked project flask-restx https://github.com/python-restx/flask-restx but still i dont think they support openapi 3.0

Im a bit confused to choose the package for my need. Im looking to solve a problem where we dont want to manually create swagger doc for our API, instead we would like to generate automatically using a packages.

import os
import requests
import json, yaml


from flask import Flask, after_this_request, send_file, safe_join, abort
from flask_restx import Resource, Api, fields
from flask_restx.api import Swagger

app = Flask(__name__)
api = Api(app=app, doc='/docs', version='1.0.0-oas3', title='TEST APP API',
          description='TEST APP API')


response_fields = api.model('Resource', {
    'value': fields.String(required=True, min_length=1, max_length=200, description='Book title')
})


@api.route('/compiler/', endpoint='compiler')
# @api.doc(params={'id': 'An ID'})
@api.doc(responses={403: 'Not Authorized'})
@api.doc(responses={402: 'Not Authorized'})
# @api.doc(responses={200: 'Not Authorized'})
class DemoList(Resource):
    @api.expect(response_fields, validate=True)
    @api.marshal_with(response_fields, code=200)
    def post(self):
        """
        returns a list of conferences
        """
        api.payload["value"] = 'Im the response ur waiting for'
        return api.payload


@api.route('/swagger')
class HelloWorld(Resource):
    def get(self):
        data = json.loads(json.dumps(api.__schema__))
        with open('yamldoc.yml', 'w') as yamlf:
            yaml.dump(data, yamlf, allow_unicode=True, default_flow_style=False)
            file = os.path.abspath(os.getcwd())
            try:
                @after_this_request
                def remove_file(resp):
                    try:
                        os.remove(safe_join(file, 'yamldoc.yml'))
                    except Exception as error:
                        log.error("Error removing or closing downloaded file handle", error)
                    return resp

                return send_file(safe_join(file, 'yamldoc.yml'), as_attachment=True, attachment_filename='yamldoc.yml', mimetype='application/x-yaml')
            except FileExistsError:
                abort(404)


# main driver function
if __name__ == '__main__':
    app.run(port=5003, debug=True)

The above code is a combination of my try on different packages, but it can generate swagger 2.0 doc but im trying to generate doc for openapi 3.0

Can some one suggest a good package which is supporting openapi 3.0 way of generating swagger yaml or json.


Solution

  • I found a package to generate openapi 3.0 document

    https://apispec.readthedocs.io/en/latest/install.html

    This package serves the purpose neatly. Find the below code for detailed usage.

    from apispec import APISpec
    from apispec.ext.marshmallow import MarshmallowPlugin
    from apispec_webframeworks.flask import FlaskPlugin
    from marshmallow import Schema, fields
    from flask import Flask, abort, request, make_response, jsonify
    from pprint import pprint
    import json
    
    
    class DemoParameter(Schema):
        gist_id = fields.Int()
    
    
    class DemoSchema(Schema):
        id = fields.Int()
        content = fields.Str()
    
    
    spec = APISpec(
        title="Demo API",
        version="1.0.0",
        openapi_version="3.0.2",
        info=dict(
            description="Demo API",
            version="1.0.0-oas3",
            contact=dict(
                email="admin@donofden.com"
                ), 
            license=dict(
                name="Apache 2.0",
                url='http://www.apache.org/licenses/LICENSE-2.0.html'
                )
            ),
        servers=[
            dict(
                description="Test server",
                url="https://resources.donofden.com"
                )
            ],
        tags=[
            dict(
                name="Demo",
                description="Endpoints related to Demo"
                )
            ],
        plugins=[FlaskPlugin(), MarshmallowPlugin()],
    )
    
    spec.components.schema("Demo", schema=DemoSchema)
    
    # spec.components.schema(
    #     "Gist",
    #     {
    #         "properties": {
    #             "id": {"type": "integer", "format": "int64"},
    #             "name": {"type": "string"},
    #         }
    #     },
    # )
    #
    # spec.path(
    #     path="/gist/{gist_id}",
    #     operations=dict(
    #         get=dict(
    #             responses={"200": {"content": {"application/json": {"schema": "Gist"}}}}
    #         )
    #     ),
    # )
    # Extensions initialization
    # =========================
    app = Flask(__name__)
    
    
    @app.route("/demo/<gist_id>", methods=["GET"])
    def my_route(gist_id):
        """Gist detail view.
        ---
        get:
          parameters:
          - in: path
            schema: DemoParameter
          responses:
            200:
              content:
                application/json:
                  schema: DemoSchema
            201:
              content:
                application/json:
                  schema: DemoSchema
        """
        # (...)
        return jsonify('foo')
    
    
    # Since path inspects the view and its route,
    # we need to be in a Flask request context
    with app.test_request_context():
        spec.path(view=my_route)
    # We're good to go! Save this to a file for now.
    with open('swagger.json', 'w') as f:
        json.dump(spec.to_dict(), f)
    
    pprint(spec.to_dict())
    print(spec.to_yaml())
    
    

    Hope this helps someone!! :)

    Update: More Detailed Documents

    Python Flask automatically generated Swagger 3.0/Openapi Document - http://donofden.com/blog/2020/06/14/Python-Flask-automatically-generated-Swagger-3-0-openapi-Document

    Python Flask automatically generated Swagger 2.0 Document - http://donofden.com/blog/2020/05/30/Python-Flask-automatically-generated-Swagger-2-0-Document