Skip to content

APIFlask

The Flask object with some web API support.

Examples:

from apiflask import APIFlask

app = APIFlask(__name__)

Attributes:

Name Type Description
openapi_version

The version of OpenAPI Specification (openapi.openapi). This attribute can also be configured from the config with the OPENAPI_VERSION configuration key. Defaults to '3.0.3'.

servers

The servers information of the API (openapi.servers), accepts multiple server dicts. Example value:

app.servers = [
    {
        'name': 'Production Server',
        'url': 'http://api.example.com'
    }
]

This attribute can also be configured from the config with the SERVERS configuration key. Defaults to None.

tags

The list of tags of the OpenAPI spec documentation (openapi.tags), accepts a list of dicts. You can also pass a simple list contains the tag name:

app.tags = ['foo', 'bar', 'baz']

A standard OpenAPI tags list will look like this:

app.tags = [
    {'name': 'foo', 'description': 'The description of foo'},
    {'name': 'bar', 'description': 'The description of bar'},
    {'name': 'baz', 'description': 'The description of baz'}
]

If not set, the blueprint names will be used as tags.

This attribute can also be configured from the config with the TAGS configuration key. Defaults to None.

external_docs

The external documentation information of the API (openapi.externalDocs). Example:

app.external_docs = {
    'description': 'Find more info here',
    'url': 'http://docs.example.com'
}

This attribute can also be configured from the config with the EXTERNAL_DOCS configuration key. Defaults to None.

info

The info object (openapi.info), it accepts a dict contains following info fields: description, termsOfService, contact, license. You can use separate configuration variables to overwrite this dict. Example:

app.info = {
    'description': '...',
    'termsOfService': 'http://example.com',
    'contact': {
        'name': 'API Support',
        'url': 'http://www.example.com/support',
        'email': 'support@example.com'
    },
    'license': {
        'name': 'Apache 2.0',
        'url': 'http://www.apache.org/licenses/LICENSE-2.0.html'
    }
}
description

The description of the API (openapi.info.description). This attribute can also be configured from the config with the DESCRIPTION configuration key. Defaults to None.

contact

The contact information of the API (openapi.info.contact). Example:

app.contact = {
    'name': 'API Support',
    'url': 'http://www.example.com/support',
    'email': 'support@example.com'
}

This attribute can also be configured from the config with the CONTACT configuration key. Defaults to None.

license

The license of the API (openapi.info.license). Example:

app.license = {
    'name': 'Apache 2.0',
    'url': 'http://www.apache.org/licenses/LICENSE-2.0.html'
}

This attribute can also be configured from the config with the LICENSE configuration key. Defaults to None.

terms_of_service

The terms of service URL of the API (openapi.info.termsOfService). Example:

app.terms_of_service = 'http://example.com/terms/'

This attribute can also be configured from the config with the TERMS_OF_SERVICE configuration key. Defaults to None.

spec_callback t.Optional[SpecCallbackType]

It stores the function object registerd by spec_processor. You can also pass a callback function to it directly without using spec_processor. Example:

def update_spec(spec):
    spec['title'] = 'Updated Title'
    return spec

app.spec_callback = update_spec
error_callback ErrorCallbackType

It stores the function object registerd by error_processor. You can also pass a callback function to it directly without using error_processor. See the docstring of error_processor for more details. Example:

def my_error_handler(error):
    return {
        'status_code': error.status_code,
        'message': error.message,
        'detail': error.detail
    }, error.status_code, error.headers

app.error_processor = my_error_handler
schema_name_resolver

It stores the function that used to decided the schema name. The schema name resolver should accept the schema object as argument and return the name. Example:

# this is the default schema name resolver used in APIFlask
def schema_name_resolver(schema):
    name = schema.__class__.__name__  # get schema class name
    if name.endswith('Schema'):  # remove the "Schema" suffix
        name = name[:-6] or name
    if schema.partial:  # add a "Update" suffix for partial schema
        name += 'Update'
    return name

app.schema_name_resolver = schema_name_resolver

Version changed: 0.9.0

  • Add instance attribute schema_name_resolver.

spec: Union[dict, str] property readonly

Get the current OAS document file.

This property will call app._get_spec() method and set the force_update parameter to True.

Version changed: 0.7.1

  • Generate the spec on every call.

__init__(self, import_name, title='APIFlask', version='0.1.0', spec_path='/openapi.json', docs_path='/docs', docs_oauth2_redirect_path='/docs/oauth2-redirect', redoc_path='/redoc', openapi_blueprint_url_prefix=None, json_errors=True, enable_openapi=True, static_url_path=None, static_folder='static', static_host=None, host_matching=False, subdomain_matching=False, template_folder='templates', instance_path=None, instance_relative_config=False, root_path=None) special

Make an app instance.

Parameters:

Name Type Description Default
import_name str

The name of the application package, usually __name__. This helps locate the root_path for the application.

required
title str

The title of the API (openapi.info.title), defaults to "APIFlask". You can change it to the name of your API (e.g., "Pet API").

'APIFlask'
version str

The version of the API (openapi.info.version), defaults to "0.1.0".

'0.1.0'
spec_path str

The path to OpenAPI Spec documentation. It defaults to /openapi.json, if the path ends with .yaml or .yml, the YAML format of the OAS will be returned.

'/openapi.json'
docs_path str

The path to Swagger UI documentation, defaults to /docs.

'/docs'
docs_oauth2_redirect_path str

The path to Swagger UI OAuth redirect.

'/docs/oauth2-redirect'
redoc_path str

The path to Redoc documentation, defaults to /redoc.

'/redoc'
openapi_blueprint_url_prefix Optional[str]

The url prefix of the OpenAPI blueprint. This prefix will append before all the OpenAPI-related paths (sepc_path, docs_path, etc.), defaults to None.

None
json_errors bool

If True, APIFlask will return a JSON response for HTTP errors.

True
enable_openapi bool

If False, will disable OpenAPI spec and API docs views.

True

Other keyword arguments are directly passed to flask.Flask.

Version changed: 0.7.0

  • Add openapi_blueprint_url_prefix argument.
Source code in apiflask/app.py
def __init__(
    self,
    import_name: str,
    title: str = 'APIFlask',
    version: str = '0.1.0',
    spec_path: str = '/openapi.json',
    docs_path: str = '/docs',
    docs_oauth2_redirect_path: str = '/docs/oauth2-redirect',
    redoc_path: str = '/redoc',
    openapi_blueprint_url_prefix: t.Optional[str] = None,
    json_errors: bool = True,
    enable_openapi: bool = True,
    static_url_path: t.Optional[str] = None,
    static_folder: str = 'static',
    static_host: t.Optional[str] = None,
    host_matching: bool = False,
    subdomain_matching: bool = False,
    template_folder: str = 'templates',
    instance_path: t.Optional[str] = None,
    instance_relative_config: bool = False,
    root_path: t.Optional[str] = None
) -> None:
    """Make an app instance.

    Arguments:
        import_name: The name of the application package, usually
            `__name__`. This helps locate the `root_path` for the
            application.
        title: The title of the API (openapi.info.title), defaults to "APIFlask".
            You can change it to the name of your API (e.g., "Pet API").
        version: The version of the API (openapi.info.version), defaults to "0.1.0".
        spec_path: The path to OpenAPI Spec documentation. It
            defaults to `/openapi.json`, if the path ends with `.yaml`
            or `.yml`, the YAML format of the OAS will be returned.
        docs_path: The path to Swagger UI documentation, defaults to `/docs`.
        docs_oauth2_redirect_path: The path to Swagger UI OAuth redirect.
        redoc_path: The path to Redoc documentation, defaults to `/redoc`.
        openapi_blueprint_url_prefix: The url prefix of the OpenAPI blueprint. This
            prefix will append before all the OpenAPI-related paths (`sepc_path`,
            `docs_path`, etc.), defaults to `None`.
        json_errors: If `True`, APIFlask will return a JSON response for HTTP errors.
        enable_openapi: If `False`, will disable OpenAPI spec and API docs views.

    Other keyword arguments are directly passed to `flask.Flask`.

    *Version changed: 0.7.0*

    - Add `openapi_blueprint_url_prefix` argument.
    """
    super().__init__(
        import_name,
        static_url_path=static_url_path,
        static_folder=static_folder,
        static_host=static_host,
        host_matching=host_matching,
        subdomain_matching=subdomain_matching,
        template_folder=template_folder,
        instance_path=instance_path,
        instance_relative_config=instance_relative_config,
        root_path=root_path
    )

    # Set default config
    self.config.from_object('apiflask.settings')

    self.title = title
    self.version = version
    self.spec_path = spec_path
    self.docs_path = docs_path
    self.redoc_path = redoc_path
    self.docs_oauth2_redirect_path = docs_oauth2_redirect_path
    self.openapi_blueprint_url_prefix = openapi_blueprint_url_prefix
    self.enable_openapi = enable_openapi
    self.json_errors = json_errors

    self.spec_callback: t.Optional[SpecCallbackType] = None
    self.error_callback: ErrorCallbackType = self._error_handler  # type: ignore
    self.schema_name_resolver = self._schema_name_resolver

    self._spec: t.Optional[t.Union[dict, str]] = None
    self._register_openapi_blueprint()
    self._register_error_handlers()

add_url_rule(self, rule, endpoint=None, view_func=None, **options)

Record the spec for view classes before calling the actual add_url_rule method.

When calling this method directly, the view_func argument can be a view function or a view function created by ViewClass.as_view(). It only accepts a view class when using the route decorator on a view class.

Source code in apiflask/app.py
def add_url_rule(
    self,
    rule: str,
    endpoint: t.Optional[str] = None,
    view_func: t.Optional[ViewFuncOrClassType] = None,
    **options: t.Any,
):
    """Record the spec for view classes before calling the actual `add_url_rule` method.

    When calling this method directly, the `view_func` argument can be a view function or
    a view function created by `ViewClass.as_view()`. It only accepts a view class when
    using the route decorator on a view class.
    """
    view_class: ViewClassType
    is_view_class: bool = False

    if hasattr(view_func, 'view_class'):
        # a function returned by MethodViewClass.as_view()
        is_view_class = True
        view_class = view_func.view_class  # type: ignore
    elif isinstance(view_func, MethodViewType):
        # a MethodView class passed with the route decorator
        is_view_class = True
        view_class = view_func  # type: ignore
        if endpoint is None:
            endpoint = view_class.__name__
        view_func = view_class.as_view(endpoint)

    if is_view_class and hasattr(self, 'enable_openapi') and self.enable_openapi:
        view_func = record_spec_for_view_class(view_func, view_class)  # type: ignore

    super(cls, self).add_url_rule(rule, endpoint, view_func, **options)

delete(self, rule, **options)

Shortcut for app.route(methods=['DELETE']).

Source code in apiflask/app.py
def delete(self, rule: str, **options: t.Any):
    """Shortcut for `app.route(methods=['DELETE'])`."""
    return _method_route(self, 'DELETE', rule, options)

dispatch_request(self)

Overwrite the default dispatch method in Flask.

With this overwrite, view arguments are passed as positional arguments so that the view function can intuitively accept the parameters (i.e., from top to bottom, from left to right).

Examples:

@app.get('/pets/<name>/<int:pet_id>/<age>')  # -> name, pet_id, age
@input(QuerySchema)  # -> query
@output(PetSchema)  # -> pet
def get_pet(name, pet_id, age, query, pet):
    pass

From Flask, see the NOTICE file for license information.

Version added: 0.2.0

Source code in apiflask/app.py
def dispatch_request(self) -> ResponseType:
    """Overwrite the default dispatch method in Flask.

    With this overwrite, view arguments are passed as positional
    arguments so that the view function can intuitively accept the
    parameters (i.e., from top to bottom, from left to right).

    Examples:

    ```python
    @app.get('/pets/<name>/<int:pet_id>/<age>')  # -> name, pet_id, age
    @input(QuerySchema)  # -> query
    @output(PetSchema)  # -> pet
    def get_pet(name, pet_id, age, query, pet):
        pass
    ```

    From Flask, see the NOTICE file for license information.

    *Version added: 0.2.0*
    """
    req = _request_ctx_stack.top.request
    if req.routing_exception is not None:
        self.raise_routing_exception(req)
    rule = req.url_rule
    # if we provide automatic options for this URL and the
    # request came with the OPTIONS method, reply automatically
    if (  # pragma: no cover
        getattr(rule, "provide_automatic_options", False)
        and req.method == "OPTIONS"
    ):
        return self.make_default_options_response()  # pragma: no cover
    # otherwise dispatch to the handler for that endpoint
    view_function = self.view_functions[rule.endpoint]
    if hasattr(self, 'ensure_sync'):  # pragma: no cover
        view_function = self.ensure_sync(view_function)
    if rule.endpoint == 'static':
        # app static route only accepts keyword arguments, see flask#3762
        return view_function(**req.view_args)  # type: ignore
    else:
        return view_function(*req.view_args.values())  # type: ignore

error_processor(self, f)

A decorator to register a custom error response processor function.

The decorated callback function will be called in the following situations:

  • Any HTTP exception is raised by Flask when APIFlask(json_errors=True) (default).
  • A validation error happened when parsing a request.
  • An exception triggered with HTTPError
  • An exception triggered with abort.

If you have set the json_errors argument to True when creating the app instance, this callback function will also be used for normal HTTP errors, for example, 404 and 500 errors, etc. You can still register a specific error handler for a specific error code or exception with the app.errorhandler(code_or_exection) decorator, in that case, the return value of the error handler will be used as the response when the corresponding error or exception happened.

The callback function must accept an error object as argument and return a valid response.

Examples:

@app.error_processor
def my_error_processor(error):
    return {
        'status_code': error.status_code,
        'message': error.message,
        'detail': error.detail,
        **error.extra_data
    }, error.status_code, error.headers

The error object is an instance of HTTPError, so you can get error information via it's attributes:

  • status_code: If the error is triggered by a validation error, the value will be 400 (default) or the value you passed in config VALIDATION_ERROR_STATUS_CODE. If the error is triggered by HTTPError or abort, it will be the status code you passed. Otherwise, it will be the status code set by Werkzueg when processing the request.
  • message: The error description for this error, either you passed or grabbed from Werkzeug.
  • detail: The detail of the error. When the validation error happens, it will be filled automatically in the following structure:

    "<location>": {
        "<field_name>": ["<error_message>", ...],
        "<field_name>": ["<error_message>", ...],
        ...
    },
    "<location>": {
        ...
    },
    ...
    

The value of location can be json (i.e., request body) or query (i.e., query string) depending on the place where the validation error happened. - headers: The value will be {} unless you pass it in HTTPError or abort. - extra_data: Additional error information.

If you want, you can rewrite the whole response body to anything you like:

@app.error_processor
def my_error_processor(error):
    body = {'error_detail': error.detail, **error.extra_data}
    return body, error.status_code, error.headers

However, I would recommend keeping the detail in the response since it contains the detailed information about the validation error when the validation error happened.

Version changed: 0.7.0

  • Support registering an async callback function.
Source code in apiflask/app.py
def error_processor(
    self,
    f: ErrorCallbackType
) -> ErrorCallbackType:
    """A decorator to register a custom error response processor function.

    The decorated callback function will be called in the following situations:

    - Any HTTP exception is raised by Flask when `APIFlask(json_errors=True)` (default).
    - A validation error happened when parsing a request.
    - An exception triggered with [`HTTPError`][apiflask.exceptions.HTTPError]
    - An exception triggered with [`abort`][apiflask.exceptions.abort].

    If you have set the `json_errors` argument to `True` when creating the `app`
    instance, this callback function will also be used for normal HTTP errors,
    for example, 404 and 500 errors, etc. You can still register a specific error
    handler for a specific error code or exception with the
    `app.errorhandler(code_or_exection)` decorator, in that case, the return
    value of the error handler will be used as the response when the corresponding
    error or exception happened.

    The callback function must accept an error object as argument and return a valid
    response.

    Examples:

    ```python
    @app.error_processor
    def my_error_processor(error):
        return {
            'status_code': error.status_code,
            'message': error.message,
            'detail': error.detail,
            **error.extra_data
        }, error.status_code, error.headers
    ```

    The error object is an instance of [`HTTPError`][apiflask.exceptions.HTTPError],
    so you can get error information via it's attributes:

    - status_code: If the error is triggered by a validation error, the value will be
      400 (default) or the value you passed in config `VALIDATION_ERROR_STATUS_CODE`.
      If the error is triggered by [`HTTPError`][apiflask.exceptions.HTTPError]
      or [`abort`][apiflask.exceptions.abort], it will be the status code
      you passed. Otherwise, it will be the status code set by Werkzueg when
      processing the request.
    - message: The error description for this error, either you passed or grabbed from
      Werkzeug.
    - detail: The detail of the error. When the validation error happens, it will
      be filled automatically in the following structure:

        ```python
        "<location>": {
            "<field_name>": ["<error_message>", ...],
            "<field_name>": ["<error_message>", ...],
            ...
        },
        "<location>": {
            ...
        },
        ...
        ```

      The value of `location` can be `json` (i.e., request body) or `query`
      (i.e., query string) depending on the place where the validation error
      happened.
    - headers: The value will be `{}` unless you pass it in `HTTPError` or `abort`.
    - extra_data: Additional error information.

    If you want, you can rewrite the whole response body to anything you like:

    ```python
    @app.error_processor
    def my_error_processor(error):
        body = {'error_detail': error.detail, **error.extra_data}
        return body, error.status_code, error.headers
    ```

    However, I would recommend keeping the `detail` in the response since it contains
    the detailed information about the validation error when the validation error
    happened.

    *Version changed: 0.7.0*

    - Support registering an async callback function.
    """
    if hasattr(self, 'ensure_sync'):  # pragma: no cover
        self.error_callback = self.ensure_sync(f)
    else:  # pragma: no cover
        self.error_callback = f
    return f

get(self, rule, **options)

Shortcut for app.route().

Source code in apiflask/app.py
def get(self, rule: str, **options: t.Any):
    """Shortcut for `app.route()`."""
    return _method_route(self, 'GET', rule, options)

patch(self, rule, **options)

Shortcut for app.route(methods=['PATCH']).

Source code in apiflask/app.py
def patch(self, rule: str, **options: t.Any):
    """Shortcut for `app.route(methods=['PATCH'])`."""
    return _method_route(self, 'PATCH', rule, options)

post(self, rule, **options)

Shortcut for app.route(methods=['POST']).

Source code in apiflask/app.py
def post(self, rule: str, **options: t.Any):
    """Shortcut for `app.route(methods=['POST'])`."""
    return _method_route(self, 'POST', rule, options)

put(self, rule, **options)

Shortcut for app.route(methods=['PUT']).

Source code in apiflask/app.py
def put(self, rule: str, **options: t.Any):
    """Shortcut for `app.route(methods=['PUT'])`."""
    return _method_route(self, 'PUT', rule, options)

spec_processor(self, f)

A decorator to register a spec handler callback function.

You can register a function to update the spec. The callback function should accept the spec as an argument and return it in the end. The callback function will be called when generating the spec file.

Examples:

@app.spec_processor
def update_spec(spec):
    spec['info']['title'] = 'Updated Title'
    return spec

Notice the format of the spec is depends on the the value of configuration variable SPEC_FORMAT (defaults to 'json'):

  • 'json' -> dict
  • 'yaml' -> string

Version Changed: 0.7.0

  • Support registering an async callback function.
Source code in apiflask/app.py
def spec_processor(self, f: SpecCallbackType) -> SpecCallbackType:
    """A decorator to register a spec handler callback function.

    You can register a function to update the spec. The callback function
    should accept the spec as an argument and return it in the end. The
    callback function will be called when generating the spec file.

    Examples:

    ```python
    @app.spec_processor
    def update_spec(spec):
        spec['info']['title'] = 'Updated Title'
        return spec
    ```

    Notice the format of the spec is depends on the the value of configuration
    variable `SPEC_FORMAT` (defaults to `'json'`):

    - `'json'` -> dict
    - `'yaml'` -> string

    *Version Changed: 0.7.0*

    - Support registering an async callback function.
    """
    if hasattr(self, 'ensure_sync'):  # pragma: no cover
        self.spec_callback = self.ensure_sync(f)
    else:  # pragma: no cover
        self.spec_callback = f
    return f