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 UIBe 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:
ProxyHeadersMiddleware by Uvicorn
SentryASGIMiddleware by Sentry
MetricsMiddleware by Prometheus
For more, check the asgi-middleware topic on github.