Swagger documentation

Swagger API documentation is automatically generated and available from your API’s root URL. You can configure the documentation using the @api.doc() decorator.

Documenting with the @api.doc() decorator

The api.doc() decorator allows you to include additional information in the documentation.

You can document a class or a method:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    def get(self, id):
        return {}

    @api.doc(responses={403: 'Not Authorized'})
    def post(self, id):
        api.abort(403)

Automatically documented models

All models instantiated with model(), clone() and inherit() will be automatically documented in your Swagger specifications.

The inherit() method will register both the parent and the child in the Swagger models definitions:

parent = api.model('Parent', {
    'name': fields.String,
    'class': fields.String(discriminator=True)
})

child = api.inherit('Child', parent, {
    'extra': fields.String
})

The above configuration will produce these Swagger definitions:

{
    "Parent": {
        "properties": {
            "name": {"type": "string"},
            "class": {"type": "string"}
        },
        "discriminator": "class",
        "required": ["class"]
    },
    "Child": {
        "allOf": [
            {
                "$ref": "#/definitions/Parent"
            }, {
                "properties": {
                    "extra": {"type": "string"}
                }
            }
        ]
    }
}

The @api.marshal_with() decorator

This decorator works like the raw marshal_with() decorator with the difference that it documents the methods. The optional parameter code allows you to specify the expected HTTP status code (200 by default). The optional parameter as_list allows you to specify whether or not the objects are returned as a list.

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>', endpoint='my-resource')
class MyResource(Resource):
    @api.marshal_with(resource_fields, as_list=True)
    def get(self):
        return get_objects()

    @api.marshal_with(resource_fields, code=201)
    def post(self):
        return create_object(), 201

The Api.marshal_list_with() decorator is strictly equivalent to Api.marshal_with(fields, as_list=True)().

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>', endpoint='my-resource')
class MyResource(Resource):
    @api.marshal_list_with(resource_fields)
    def get(self):
        return get_objects()

    @api.marshal_with(resource_fields)
    def post(self):
        return create_object()

The @api.expect() decorator

The @api.expect() decorator allows you to specify the expected input fields. It accepts an optional boolean parameter validate indicating whether the payload should be validated. The validation behavior can be customized globally either by setting the RESTX_VALIDATE configuration to True or passing validate=True to the API constructor.

The following examples are equivalent:

  • Using the @api.expect() decorator:

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    @api.expect(resource_fields)
    def get(self):
        pass
  • Using the api.doc() decorator:

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    @api.doc(body=resource_fields)
    def get(self):
        pass

You can specify lists as the expected input:

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    @api.expect([resource_fields])
    def get(self):
        pass

You can use RequestParser to define the expected input:

parser = api.parser()
parser.add_argument('param', type=int, help='Some param', location='form')
parser.add_argument('in_files', type=FileStorage, location='files')


@api.route('/with-parser/', endpoint='with-parser')
class WithParserResource(restx.Resource):
    @api.expect(parser)
    def get(self):
        return {}

Validation can be enabled or disabled on a particular endpoint:

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    # Payload validation disabled
    @api.expect(resource_fields)
    def post(self):
        pass

    # Payload validation enabled
    @api.expect(resource_fields, validate=True)
    def post(self):
        pass

An example of application-wide validation by config:

app.config['RESTX_VALIDATE'] = True

api = Api(app)

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    # Payload validation enabled
    @api.expect(resource_fields)
    def post(self):
        pass

    # Payload validation disabled
    @api.expect(resource_fields, validate=False)
    def post(self):
        pass

An example of application-wide validation by constructor:

api = Api(app, validate=True)

resource_fields = api.model('Resource', {
    'name': fields.String,
})

@api.route('/my-resource/<id>')
class MyResource(Resource):
    # Payload validation enabled
    @api.expect(resource_fields)
    def post(self):
        pass

    # Payload validation disabled
    @api.expect(resource_fields, validate=False)
    def post(self):
        pass

Documenting with the @api.response() decorator

The @api.response() decorator allows you to document the known responses and is a shortcut for @api.doc(responses='...').

The following two definitions are equivalent:

@api.route('/my-resource/')
class MyResource(Resource):
    @api.response(200, 'Success')
    @api.response(400, 'Validation Error')
    def get(self):
        pass


@api.route('/my-resource/')
class MyResource(Resource):
    @api.doc(responses={
        200: 'Success',
        400: 'Validation Error'
    })
    def get(self):
        pass

You can optionally specify a response model as the third argument:

model = api.model('Model', {
    'name': fields.String,
})

@api.route('/my-resource/')
class MyResource(Resource):
    @api.response(200, 'Success', model)
    def get(self):
        pass

The @api.marshal_with() decorator automatically documents the response:

model = api.model('Model', {
    'name': fields.String,
})

@api.route('/my-resource/')
class MyResource(Resource):
    @api.response(400, 'Validation error')
    @api.marshal_with(model, code=201, description='Object created')
    def post(self):
        pass

You can specify a default response sent without knowing the response code:

@api.route('/my-resource/')
class MyResource(Resource):
    @api.response('default', 'Error')
    def get(self):
        pass

The @api.route() decorator

You can provide class-wide documentation using the doc parameter of Api.route(). This parameter accepts the same values as the Api.doc() decorator.

For example, these two declarations are equivalent:

  • Using @api.doc():

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    def get(self, id):
        return {}
  • Using @api.route():

@api.route('/my-resource/<id>', endpoint='my-resource', doc={'params':{'id': 'An ID'}})
class MyResource(Resource):
    def get(self, id):
        return {}

Multiple Routes per Resource

Multiple Api.route() decorators can be used to add multiple routes for a Resource. The doc parameter provides documentation per route.

For example, here the description is applied only to the /also-my-resource/<id> route:

@api.route("/my-resource/<id>")
@api.route(
    "/also-my-resource/<id>",
    doc={"description": "Alias for /my-resource/<id>"},
)
class MyResource(Resource):
    def get(self, id):
        return {}

Here, the /also-my-resource/<id> route is marked as deprecated:

@api.route("/my-resource/<id>")
@api.route(
    "/also-my-resource/<id>",
    doc={
        "description": "Alias for /my-resource/<id>, this route is being phased out in V2",
        "deprecated": True,
    },
)
class MyResource(Resource):
    def get(self, id):
        return {}

Documentation applied to the Resource using Api.doc() is shared amongst all routes unless explicitly overridden:

@api.route("/my-resource/<id>")
@api.route(
"/also-my-resource/<id>",
doc={"description": "Alias for /my-resource/<id>"},
)
@api.doc(params={"id": "An ID", description="My resource"})
class MyResource(Resource):
def get(self, id):
    return {}

Here, the id documentation from the @api.doc() decorator is present in both routes, /my-resource/<id> inherits the My resource description from the @api.doc() decorator and /also-my-resource/<id> overrides the description with Alias for /my-resource/<id>.

Routes with a doc parameter are given a unique Swagger operationId. Routes without doc parameter have the same Swagger operationId as they are deemed the same operation.

Documenting the fields

Every Flask-RESTX field accepts optional arguments used to document the field:

  • required: a boolean indicating if the field is always set (default: False)

  • description: some details about the field (default: None)

  • example: an example to use when displaying (default: None)

There are also field-specific attributes:

  • The String field accepts the following optional arguments:
    • enum: an array restricting the authorized values.

    • min_length: the minimum length expected.

    • max_length: the maximum length expected.

    • pattern: a RegExp pattern used to validate the string.

  • The Integer, Float and Arbitrary fields accept the following optional arguments:
    • min: restrict the minimum accepted value.

    • max: restrict the maximum accepted value.

    • exclusiveMin: if True, minimum value is not in allowed interval.

    • exclusiveMax: if True, maximum value is not in allowed interval.

    • multiple: specify that the number must be a multiple of this value.

  • The DateTime field accepts the min, max, exclusiveMin and exclusiveMax optional arguments. These should be dates or datetimes (either ISO strings or native objects).

my_fields = api.model('MyModel', {
    'name': fields.String(description='The name', required=True),
    'type': fields.String(description='The object type', enum=['A', 'B']),
    'age': fields.Integer(min=0),
})

Documenting the methods

Each resource will be documented as a Swagger path.

Each resource method (get, post, put, delete, path, options, head) will be documented as a Swagger operation.

You can specify a unique Swagger operationId with the id keyword argument:

@api.route('/my-resource/')
class MyResource(Resource):
    @api.doc(id='get_something')
    def get(self):
        return {}

You can also use the first argument for the same purpose:

@api.route('/my-resource/')
class MyResource(Resource):
    @api.doc('get_something')
    def get(self):
        return {}

If not specified, a default operationId is provided with the following pattern:

{{verb}}_{{resource class name | camelCase2dashes }}

In the previous example, the default generated operationId would be get_my_resource.

You can override the default operationId generator by providing a callable for the default_id parameter. This callable accepts two positional arguments:

  • The resource class name

  • The HTTP method (lower-case)

def default_id(resource, method):
    return ''.join((method, resource))

api = Api(app, default_id=default_id)

In the previous example, the generated operationId would be getMyResource.

Each operation will automatically receive the namespace tag. If the resource is attached to the root API, it will receive the default namespace tag.

Method parameters

Parameters from the URL path are documented automatically. You can provide additional information using the params keyword argument of the api.doc() decorator:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    pass

or by using the api.param shortcut decorator:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.param('id', 'An ID')
class MyResource(Resource):
    pass

Input and output models

You can specify the serialized output model using the model keyword argument of the api.doc() decorator.

For POST and PUT methods, use the body keyword argument to specify the input model.

my_model = api.model('MyModel', {
    'name': fields.String(description='The name', required=True),
    'type': fields.String(description='The object type', enum=['A', 'B']),
    'age': fields.Integer(min=0),
})


class Person(fields.Raw):
    def format(self, value):
        return {'name': value.name, 'age': value.age}


@api.route('/my-resource/<id>', endpoint='my-resource')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    @api.doc(model=my_model)
    def get(self, id):
        return {}

    @api.doc(model=my_model, body=Person)
    def post(self, id):
        return {}

If both body and formData parameters are used, a SpecsError will be raised.

Models can also be specified with a RequestParser.

parser = api.parser()
parser.add_argument('param', type=int, help='Some param', location='form')
parser.add_argument('in_files', type=FileStorage, location='files')

@api.route('/with-parser/', endpoint='with-parser')
class WithParserResource(restx.Resource):
    @api.expect(parser)
    def get(self):
        return {}

Note

The decoded payload will be available as a dictionary in the payload attribute in the request context.

@api.route('/my-resource/')
class MyResource(Resource):
    def get(self):
        data = api.payload

Note

Using RequestParser is preferred over the api.param() decorator to document form fields as it also perform validation.

Headers

You can document response headers with the @api.header() decorator shortcut.

@api.route('/with-headers/')
@api.header('X-Header', 'Some class header')
class WithHeaderResource(restx.Resource):
    @api.header('X-Collection', type=[str], collectionType='csv')
    def get(self):
        pass

If you need to specify an header that appear only on a given response, just use the @api.response headers parameter.

@api.route('/response-headers/')
class WithHeaderResource(restx.Resource):
    @api.response(200, 'Success', headers={'X-Header': 'Some header'})
    def get(self):
        pass

Documenting expected/request headers is done through the @api.expect decorator

parser = api.parser()
parser.add_argument('Some-Header', location='headers')

@api.route('/expect-headers/')
@api.expect(parser)
class ExpectHeaderResource(restx.Resource):
    def get(self):
        pass

Cascading

Method documentation takes precedence over class documentation, and inherited documentation takes precedence over parent documentation.

For example, these two declarations are equivalent:

  • Class documentation is inherited by methods:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.params('id', 'An ID')
class MyResource(Resource):
    def get(self, id):
        return {}
  • Class documentation is overridden by method-specific documentation:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.param('id', 'Class-wide description')
class MyResource(Resource):
    @api.param('id', 'An ID')
    def get(self, id):
        return {}

You can also provide method-specific documentation from a class decorator. The following example will produce the same documentation as the two previous examples:

@api.route('/my-resource/<id>', endpoint='my-resource')
@api.params('id', 'Class-wide description')
@api.doc(get={'params': {'id': 'An ID'}})
class MyResource(Resource):
    def get(self, id):
        return {}

Marking as deprecated

You can mark resources or methods as deprecated with the @api.deprecated decorator:

# Deprecate the full resource
@api.deprecated
@api.route('/resource1/')
class Resource1(Resource):
    def get(self):
        return {}

# Deprecate methods
@api.route('/resource4/')
class Resource4(Resource):
    def get(self):
        return {}

    @api.deprecated
    def post(self):
        return {}

    def put(self):
        return {}

Hiding from documentation

You can hide some resources or methods from documentation using any of the following:

# Hide the full resource
@api.route('/resource1/', doc=False)
class Resource1(Resource):
    def get(self):
        return {}

@api.route('/resource2/')
@api.doc(False)
class Resource2(Resource):
    def get(self):
        return {}

@api.route('/resource3/')
@api.hide
class Resource3(Resource):
    def get(self):
        return {}

# Hide methods
@api.route('/resource4/')
@api.doc(delete=False)
class Resource4(Resource):
    def get(self):
        return {}

    @api.doc(False)
    def post(self):
        return {}

    @api.hide
    def put(self):
        return {}

    def delete(self):
        return {}

Note

Namespace tags without attached resources will be hidden automatically from the documentation.

Documenting authorizations

You can use the authorizations keyword argument to document authorization information. See Swagger Authentication documentation for configuration details.

  • authorizations is a Python dictionary representation of the Swagger securityDefinitions configuration.

authorizations = {
    'apikey': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'X-API-KEY'
    }
}
api = Api(app, authorizations=authorizations)

Then decorate each resource and method that requires authorization:

@api.route('/resource/')
class Resource1(Resource):
    @api.doc(security='apikey')
    def get(self):
        pass

    @api.doc(security='apikey')
    def post(self):
        pass

You can apply this requirement globally with the security parameter on the Api constructor:

authorizations = {
    'apikey': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'X-API-KEY'
    }
}
api = Api(app, authorizations=authorizations, security='apikey')

You can have multiple security schemes:

authorizations = {
    'apikey': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'X-API'
    },
    'oauth2': {
        'type': 'oauth2',
        'flow': 'accessCode',
        'tokenUrl': 'https://somewhere.com/token',
        'authorizationUrl': 'https://somewhere.com/auth',
        'scopes': {
            'read': 'Grant read-only access',
            'write': 'Grant read-write access',
        }
    }
}
api = Api(self.app, security=['apikey', {'oauth2': 'read'}], authorizations=authorizations)

Security schemes can be overridden for a particular method:

@api.route('/authorizations/')
class Authorized(Resource):
    @api.doc(security=[{'oauth2': ['read', 'write']}])
    def get(self):
        return {}

You can disable security on a given resource or method by passing None or an empty list as the security parameter:

@api.route('/without-authorization/')
class WithoutAuthorization(Resource):
    @api.doc(security=[])
    def get(self):
        return {}

    @api.doc(security=None)
    def post(self):
        return {}

Expose vendor Extensions

Swaggers allows you to expose custom vendor extensions and you can use them in Flask-RESTX with the @api.vendor decorator.

It supports both extensions as dict or kwargs and perform automatique x- prefix:

@api.route('/vendor/')
@api.vendor(extension1='any authorized value')
class Vendor(Resource):
    @api.vendor({
        'extension-1': {'works': 'with complex values'},
        'x-extension-3': 'x- prefix is optional',
    })
    def get(self):
        return {}

Export Swagger specifications

You can export the Swagger specifications for your API:

from flask import json

from myapp import api

print(json.dumps(api.__schema__))

Swagger UI

By default flask-restx provides Swagger UI documentation, served from the root URL of the API.

from flask import Flask
from flask_restx import Api, Resource, fields

app = Flask(__name__)
api = Api(app, version='1.0', title='Sample API',
    description='A sample API',
)

@api.route('/my-resource/<id>')
@api.doc(params={'id': 'An ID'})
class MyResource(Resource):
    def get(self, id):
        return {}

    @api.response(403, 'Not Authorized')
    def post(self, id):
        api.abort(403)


if __name__ == '__main__':
    app.run(debug=True)

If you run the code below and visit your API’s root URL (http://localhost:5000) you can view the automatically-generated Swagger UI documentation.

_images/screenshot-apidoc-quickstart.png

Customization

You can control the Swagger UI path with the doc parameter (defaults to the API root):

from flask import Flask, Blueprint
from flask_restx import Api

app = Flask(__name__)
blueprint = Blueprint('api', __name__, url_prefix='/api')
api = Api(blueprint, doc='/doc/')

app.register_blueprint(blueprint)

assert url_for('api.doc') == '/api/doc/'

You can specify a custom validator URL by setting config.SWAGGER_VALIDATOR_URL:

from flask import Flask
from flask_restx import Api

app = Flask(__name__)
app.config.SWAGGER_VALIDATOR_URL = 'http://domain.com/validator'

api = Api(app)

You can enable [OAuth2 Implicit Flow](https://oauth.net/2/grant-types/implicit/) for retrieving an authorization token for testing api endpoints interactively within Swagger UI. The config.SWAGGER_UI_OAUTH_CLIENT_ID and authorizationUrl and scopes will be specific to your OAuth2 IDP configuration. The realm string is added as a query parameter to authorizationUrl and tokenUrl. These values are all public knowledge. No client secret is specified here. .. Using PKCE instead of Implicit Flow depends on https://github.com/swagger-api/swagger-ui/issues/5348

from flask import Flask
from flask_restx import Api

app = Flask(__name__)

app.config.SWAGGER_UI_OAUTH_CLIENT_ID = 'MyClientId'
app.config.SWAGGER_UI_OAUTH_REALM = '-'
app.config.SWAGGER_UI_OAUTH_APP_NAME = 'Demo'

api = Api(
    app,
    title=app.config.SWAGGER_UI_OAUTH_APP_NAME,
    security={'OAuth2': ['read', 'write']},
    authorizations={
        'OAuth2': {
            'type': 'oauth2',
            'flow': 'implicit',
            'authorizationUrl': 'https://idp.example.com/authorize?audience=https://app.example.com',
            'clientId': app.config.SWAGGER_UI_OAUTH_CLIENT_ID,
            'scopes': {
                'openid': 'Get ID token',
                'profile': 'Get identity',
            }
        }
    }
)

You can also specify the initial expansion state with the config.SWAGGER_UI_DOC_EXPANSION setting ('none', 'list' or 'full'):

from flask import Flask
from flask_restx import Api

app = Flask(__name__)
app.config.SWAGGER_UI_DOC_EXPANSION = 'list'

api = Api(app)

By default, operation ID is hidden as well as request duration, you can enable them respectively with:

from flask import Flask
from flask_restx import Api

app = Flask(__name__)
app.config.SWAGGER_UI_OPERATION_ID = True
app.config.SWAGGER_UI_REQUEST_DURATION = True

api = Api(app)

If you need a custom UI, you can register a custom view function with the documentation() decorator:

from flask import Flask
from flask_restx import Api, apidoc

app = Flask(__name__)
api = Api(app)

@api.documentation
def custom_ui():
    return apidoc.ui_for(api)

Configuring “Try it Out”

By default, all paths and methods have a “Try it Out” button for performing API requests in the browser. These can be disable per method with the SWAGGER_SUPPORTED_SUBMIT_METHODS configuration option, supporting the same values as the supportedSubmitMethods Swagger UI parameter.

from flask import Flask
from flask_restx import Api

app = Flask(__name__)

# disable Try it Out for all methods
app.config.SWAGGER_SUPPORTED_SUBMIT_METHODS = []

# enable Try it Out for specific methods
app.config.SWAGGER_SUPPORTED_SUBMIT_METHODS = ["get", "post"]

api = Api(app)

Disabling the documentation

To disable Swagger UI entirely, set doc=False:

from flask import Flask
from flask_restx import Api

app = Flask(__name__)
api = Api(app, doc=False)