Middleware

Connexion is built as an ASGI middleware stack wrapping an application. It includes several middlewares by default that add functionality based on the OpenAPI specification, in the following order:

ServerErrorMiddleware

Returns server errors for any exceptions not caught by the ExceptionMiddleware

ExceptionMiddleware

Handles exceptions raised by the middleware stack or application

SwaggerUIMiddleware

Adds a Swagger UI to your application

RoutingMiddleware

Routes incoming requests to the right operation defined in the specification

SecurityMiddleware

Checks incoming requests against the security defined in the specification

RequestValidationMiddleware

Validates the incoming requests against the spec

ResponseValidationMiddleware

Validates the returned responses against the spec, if activated

LifespanMiddleware

Allows registration of code to run before application start-up or after shut-down

ContextMiddleware

Makes several request scoped context variables available to the application

Adding middleware

You can easily add additional ASGI middleware to the middleware stack with the add_middleware method:

from connexion import AsyncApp

app = AsyncApp(__name__)

app.add_middleware(MiddlewareClass, **options)
View a detailed reference of the add_middleware method
AsyncApp.add_middleware(middleware_class: Type[Callable[[MutableMapping[str, Any], Callable[[], Awaitable[MutableMapping[str, Any]]], Callable[[MutableMapping[str, Any]], Awaitable[None]]], Awaitable[None]]], position: MiddlewarePosition = MiddlewarePosition.BEFORE_CONTEXT, **options: Any) None

Add a middleware to the stack on the specified position.

Parameters:
  • middleware_class – Middleware class to add

  • position – Position to add the middleware, one of the MiddlewarePosition Enum

  • options – Options to pass to the middleware_class on initialization

from connexion import FlaskApp

app = FlaskApp(__name__)

app.add_middleware(MiddlewareClass, **options)
View a detailed reference of the add_middleware method
FlaskApp.add_middleware(middleware_class: Type[Callable[[MutableMapping[str, Any], Callable[[], Awaitable[MutableMapping[str, Any]]], Callable[[MutableMapping[str, Any]], Awaitable[None]]], Awaitable[None]]], position: MiddlewarePosition = MiddlewarePosition.BEFORE_CONTEXT, **options: Any) None

Add a middleware to the stack on the specified position.

Parameters:
  • middleware_class – Middleware class to add

  • position – Position to add the middleware, one of the MiddlewarePosition Enum

  • options – Options to pass to the middleware_class on initialization

You can also add WSGI middleware to a FlaskApp. Note that it will only be called at the end of the middleware stack. If you need your middleware to act sooner, you will have to use an ASGI middleware instead.

app.add_wsgi_middleware(MiddlewareClass, **options)
View a detailed reference of the add_middleware method
FlaskApp.add_wsgi_middleware(middleware: Type[Callable[[Mapping[str, object], Union[Callable[[str, Sequence[Tuple[str, str]]], Callable[[bytes], Any]], Callable[[str, Sequence[Tuple[str, str]], Optional[Tuple[type, BaseException, TracebackType]]], Callable[[bytes], Any]]]], Iterable[bytes]]], **options: Any) None

Wrap the underlying Flask application with a WSGI middleware. Note that it will only be called at the end of the middleware stack. Middleware that needs to act sooner, needs to be added as ASGI middleware instead.

Adding multiple middleware using this method wraps each middleware around the previous one.

Parameters:
  • middleware – Middleware class to add

  • options – Options to pass to the middleware_class on initialization

from asgi_framework import App
from connexion import ConnexionMiddleware

app = App(__name__)
app = ConnexionMiddleware(app)

app.add_middleware(MiddlewareClass, **options)
View a detailed reference of the add_wsgi_middleware method
ConnexionMiddleware.add_middleware(middleware_class: Type[Callable[[MutableMapping[str, Any], Callable[[], Awaitable[MutableMapping[str, Any]]], Callable[[MutableMapping[str, Any]], Awaitable[None]]], Awaitable[None]]], *, position: MiddlewarePosition = MiddlewarePosition.BEFORE_CONTEXT, **options: Any) None

Add a middleware to the stack on the specified position.

Parameters:
  • middleware_class – Middleware class to add

  • position – Position to add the middleware, one of the MiddlewarePosition Enum

  • options – Options to pass to the middleware_class on initialization

Middleware order

The add_middleware method takes a position argument to define where in the middleware stack it should be inserted, which should be an instance of the MiddlewarePosition Enum. The positions below are ordered from outer to inner, in the order they are hit by incoming requests. Note that responses hit the middlewares in reversed order.

class connexion.middleware.MiddlewarePosition(value)

Positions to insert a middleware

BEFORE_EXCEPTION

Add before the ExceptionMiddleware. This is useful if you want your changes to affect the way exceptions are handled, such as a custom error handler.

Be mindful that security has not yet been applied at this stage. Additionally, the inserted middleware is positioned before the RoutingMiddleware, so you cannot leverage any routing information yet and should implement your middleware to work globally instead of on an operation level.

Useful for middleware which should also be applied to error responses. Note that errors raised here will not be handled by the exception handlers and will always result in an internal server error response.

BEFORE_SWAGGER

Add before the SwaggerUIMiddleware. This is useful if you want your changes to affect the Swagger UI, such as a path altering middleware that should also alter the paths exposed by the Swagger UI

Be mindful that security has not yet been applied at this stage.

Since the inserted middleware is positioned before the RoutingMiddleware, you cannot leverage any routing information yet and should implement your middleware to work globally instead of on an operation level.

BEFORE_ROUTING

Add before the RoutingMiddleware. This is useful if you want your changes to be applied before hitting the router, such as for path altering or CORS middleware.

Be mindful that security has not yet been applied at this stage.

Since the inserted middleware is positioned before the RoutingMiddleware, you cannot leverage any routing information yet and should implement your middleware to work globally instead of on an operation level.

BEFORE_SECURITY

Add before the SecurityMiddleware. Insert middleware here that needs to be able to adapt incoming requests before security is applied.

Be mindful that security has not yet been applied at this stage.

Since the inserted middleware is positioned after the RoutingMiddleware, you can leverage routing information and implement the middleware to work on an individual operation level.

BEFORE_VALIDATION

Add before the RequestValidationMiddleware. Insert middleware here that needs to be able to adapt incoming requests before they are validated.

Since the inserted middleware is positioned after the RoutingMiddleware, you can leverage routing information and implement the middleware to work on an individual operation level.

BEFORE_CONTEXT

Add before the ContextMiddleware, near the end of the stack. This is the default location. The inserted middleware is only followed by the ContextMiddleware, which ensures any changes to the context are properly exposed to the application.

Since the inserted middleware is positioned after the RoutingMiddleware, you can leverage routing information and implement the middleware to work on an individual operation level.

Since the inserted middleware is positioned after the ResponseValidationMiddleware, it can intercept responses coming from the application and alter them before they are validated.

Customizing the middleware stack

If you need more flexibility, or want to modify or delete any of the default middlewares, you can also pass in a customized middleware stack when instantiating your application.

For example, if you would like to remove the SecurityMiddleware since you are handling Security through an API Gateway in front of your application, you can do:

from connexion import AsyncApp, ConnexionMiddleware
from connexion.middleware.security import SecurityMiddleware

middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
               if middleware is not SecurityMiddleware]

app = AsyncApp(__name__, middlewares=middlewares)
View a detailed reference of the AsyncApp __init__ method
class connexion.AsyncApp(import_name: str, *, lifespan: Optional[Callable[[Any], AbstractAsyncContextManager]] = None, middlewares: Optional[list] = None, specification_dir: Union[Path, str] = '', arguments: Optional[dict] = None, auth_all_paths: Optional[bool] = None, jsonifier: Optional[Jsonifier] = None, pythonic_params: Optional[bool] = None, resolver: Optional[Union[Resolver, Callable]] = None, resolver_error: Optional[int] = None, strict_validation: Optional[bool] = None, swagger_ui_options: Optional[SwaggerUIOptions] = None, uri_parser_class: Optional[AbstractURIParser] = None, validate_responses: Optional[bool] = None, validator_map: Optional[dict] = None, security_map: Optional[dict] = None)

Connexion Application based on ConnexionMiddleware wrapping a async Connexion application based on starlette tools.

Parameters:
  • import_name – The name of the package or module that this object belongs to. If you are using a single module, __name__ is always the correct value. If you however are using a package, it’s usually recommended to hardcode the name of your package there.

  • lifespan – A lifespan context function, which can be used to perform startup and shutdown tasks.

  • middlewares – The list of middlewares to wrap around the application. Defaults to middleware.main.ConnexionMiddleware.default_middlewares

  • specification_dir – The directory holding the specification(s). The provided path should either be absolute or relative to the root path of the application. Defaults to the root path.

  • arguments – Arguments to substitute the specification using Jinja.

  • auth_all_paths – whether to authenticate not paths not defined in the specification. Defaults to False.

  • jsonifier – Custom jsonifier to overwrite json encoding for json responses.

  • pythonic_params – When True, CamelCase parameters are converted to snake_case and an underscore is appended to any shadowed built-ins. Defaults to False.

  • resolver – Callable that maps operationId to a function or instance of resolver.Resolver.

  • resolver_error – Error code to return for operations for which the operationId could not be resolved. If no error code is provided, the application will fail when trying to start.

  • strict_validation – When True, extra form or query parameters not defined in the specification result in a validation error. Defaults to False.

  • swagger_ui_options – Instance of options.ConnexionOptions with configuration options for the swagger ui.

  • uri_parser_class – Class to use for uri parsing. See uri_parsing.

  • validate_responses – Whether to validate responses against the specification. This has an impact on performance. Defaults to False.

  • validator_map – A dictionary of validators to use. Defaults to validators.VALIDATOR_MAP.

  • security_map – A dictionary of security handlers to use. Defaults to security.SECURITY_HANDLERS

from connexion import FlaskApp, ConnexionMiddleware
from connexion.middleware.security import SecurityMiddleware

middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
               if middleware is not SecurityMiddleware]

app = FlaskApp(__name__, middlewares=middlewares)
View a detailed reference of the FlaskApp __init__ method
class connexion.FlaskApp(import_name: str, *, lifespan: Optional[Callable[[Any], AbstractAsyncContextManager]] = None, middlewares: Optional[list] = None, server_args: Optional[dict] = None, specification_dir: Union[Path, str] = '', arguments: Optional[dict] = None, auth_all_paths: Optional[bool] = None, jsonifier: Optional[Jsonifier] = None, pythonic_params: Optional[bool] = None, resolver: Optional[Union[Resolver, Callable]] = None, resolver_error: Optional[int] = None, strict_validation: Optional[bool] = None, swagger_ui_options: Optional[SwaggerUIOptions] = None, uri_parser_class: Optional[AbstractURIParser] = None, validate_responses: Optional[bool] = None, validator_map: Optional[dict] = None, security_map: Optional[dict] = None)

Connexion Application based on ConnexionMiddleware wrapping a Flask application.

Parameters:
  • import_name – The name of the package or module that this object belongs to. If you are using a single module, __name__ is always the correct value. If you however are using a package, it’s usually recommended to hardcode the name of your package there.

  • lifespan – A lifespan context function, which can be used to perform startup and shutdown tasks.

  • middlewares – The list of middlewares to wrap around the application. Defaults to middleware.main.ConnexionMiddleware.default_middlewares

  • server_args – Arguments to pass to the Flask application.

  • specification_dir – The directory holding the specification(s). The provided path should either be absolute or relative to the root path of the application. Defaults to the root path.

  • arguments – Arguments to substitute the specification using Jinja.

  • auth_all_paths – whether to authenticate not paths not defined in the specification. Defaults to False.

  • jsonifier – Custom jsonifier to overwrite json encoding for json responses.

  • swagger_ui_options – A options.ConnexionOptions instance with configuration options for the swagger ui.

  • pythonic_params – When True, CamelCase parameters are converted to snake_case and an underscore is appended to any shadowed built-ins. Defaults to False.

  • resolver – Callable that maps operationId to a function or instance of resolver.Resolver.

  • resolver_error – Error code to return for operations for which the operationId could not be resolved. If no error code is provided, the application will fail when trying to start.

  • strict_validation – When True, extra form or query parameters not defined in the specification result in a validation error. Defaults to False.

  • swagger_ui_options – Instance of options.ConnexionOptions with configuration options for the swagger ui.

  • uri_parser_class – Class to use for uri parsing. See uri_parsing.

  • validate_responses – Whether to validate responses against the specification. This has an impact on performance. Defaults to False.

  • validator_map – A dictionary of validators to use. Defaults to validators.VALIDATOR_MAP.

  • security_map – A dictionary of security handlers to use. Defaults to security.SECURITY_HANDLERS

from asgi_framework import App
from connexion import ConnexionMiddleware
from connexion.middleware.security import SecurityMiddleware

middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
               if middleware is not SecurityMiddleware]

app = App(__name__)
app = ConnexionMiddleware(app, middlewares=middlewares)
View a detailed reference of the ConnexionMiddleware __init__ method
class connexion.ConnexionMiddleware(app: Callable[[MutableMapping[str, Any], Callable[[], Awaitable[MutableMapping[str, Any]]], Callable[[MutableMapping[str, Any]], Awaitable[None]]], Awaitable[None]], *, import_name: Optional[str] = None, lifespan: Optional[Callable[[Any], AbstractAsyncContextManager]] = None, middlewares: Optional[List[Callable[[MutableMapping[str, Any], Callable[[], Awaitable[MutableMapping[str, Any]]], Callable[[MutableMapping[str, Any]], Awaitable[None]]], Awaitable[None]]]] = None, specification_dir: Union[Path, str] = '', arguments: Optional[dict] = None, auth_all_paths: Optional[bool] = None, jsonifier: Optional[Jsonifier] = None, pythonic_params: Optional[bool] = None, resolver: Optional[Union[Resolver, Callable]] = None, resolver_error: Optional[int] = None, strict_validation: Optional[bool] = None, swagger_ui_options: Optional[SwaggerUIOptions] = None, uri_parser_class: Optional[AbstractURIParser] = None, validate_responses: Optional[bool] = None, validator_map: Optional[dict] = None, security_map: Optional[dict] = None)

The main Connexion middleware, which wraps a list of specialized middlewares around the provided application.

Parameters:
  • import_name – The name of the package or module that this object belongs to. If you are using a single module, __name__ is always the correct value. If you however are using a package, it’s usually recommended to hardcode the name of your package there.

  • middlewares – The list of middlewares to wrap around the application. Defaults to middleware.main.ConnexionmMiddleware.default_middlewares

  • specification_dir – The directory holding the specification(s). The provided path should either be absolute or relative to the root path of the application. Defaults to the root path.

  • arguments – Arguments to substitute the specification using Jinja.

  • auth_all_paths – whether to authenticate not paths not defined in the specification. Defaults to False.

  • jsonifier – Custom jsonifier to overwrite json encoding for json responses.

  • pythonic_params – When True, CamelCase parameters are converted to snake_case and an underscore is appended to any shadowed built-ins. Defaults to False.

  • resolver – Callable that maps operationId to a function or instance of resolver.Resolver.

  • resolver_error – Error code to return for operations for which the operationId could not be resolved. If no error code is provided, the application will fail when trying to start.

  • strict_validation – When True, extra form or query parameters not defined in the specification result in a validation error. Defaults to False.

  • swagger_ui_options – Instance of options.ConnexionOptions with configuration options for the swagger ui.

  • uri_parser_class – Class to use for uri parsing. See uri_parsing.

  • validate_responses – Whether to validate responses against the specification. This has an impact on performance. Defaults to False.

  • validator_map – A dictionary of validators to use. Defaults to validators.VALIDATOR_MAP.

  • security_map – A dictionary of security handlers to use. Defaults to security.SECURITY_HANDLERS.

Writing custom middleware

You can add any custom middleware as long as it implements the ASGI interface. To learn how to write pure ASGI middleware, please refer to the documentation of starlette.

List of useful middleware

Starlette provides a bunch of useful middleware such as:

Other useful middleware:

For more, check the asgi-middleware topic on github.