mirror of
https://github.com/LukeHagar/connexion.git
synced 2025-12-06 04:19:26 +00:00
Add middleware documentation (#1706)
Contributes towards https://github.com/spec-first/connexion/issues/1531 This PR adds a documentation page on middleware.
This commit is contained in:
@@ -87,12 +87,66 @@ class _Options:
|
||||
|
||||
|
||||
class MiddlewarePosition(enum.Enum):
|
||||
"""Positions to insert a middleware"""
|
||||
|
||||
BEFORE_SWAGGER = SwaggerUIMiddleware
|
||||
"""Add before the :class:`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.
|
||||
|
||||
:meta hide-value:
|
||||
"""
|
||||
BEFORE_ROUTING = RoutingMiddleware
|
||||
"""Add before the :class:`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.
|
||||
|
||||
:meta hide-value:
|
||||
"""
|
||||
BEFORE_SECURITY = SecurityMiddleware
|
||||
"""Add before the :class:`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.
|
||||
|
||||
:meta hide-value:
|
||||
"""
|
||||
BEFORE_VALIDATION = RequestValidationMiddleware
|
||||
"""Add before the :class:`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.
|
||||
|
||||
:meta hide-value:
|
||||
"""
|
||||
BEFORE_CONTEXT = ContextMiddleware
|
||||
"""Add before the :class:`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.
|
||||
|
||||
:meta hide-value:
|
||||
"""
|
||||
|
||||
|
||||
class API:
|
||||
|
||||
@@ -63,6 +63,7 @@ Documentation
|
||||
:maxdepth: 2
|
||||
|
||||
quickstart
|
||||
middleware
|
||||
cli
|
||||
routing
|
||||
request
|
||||
|
||||
205
docs/middleware.rst
Normal file
205
docs/middleware.rst
Normal file
@@ -0,0 +1,205 @@
|
||||
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:
|
||||
|
||||
.. csv-table::
|
||||
:widths: 30, 70
|
||||
|
||||
**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
|
||||
:code:`add_middleware` method:
|
||||
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: AsyncApp
|
||||
:sync: AsyncApp
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from connexion import AsyncApp
|
||||
|
||||
app = AsyncApp(__name__)
|
||||
|
||||
app.add_middleware(MiddlewareClass, **options)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :code:`add_middleware` method
|
||||
:icon: eye
|
||||
|
||||
.. automethod:: connexion.AsyncApp.add_middleware
|
||||
:noindex:
|
||||
|
||||
.. tab-item:: FlaskApp
|
||||
:sync: FlaskApp
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from connexion import FlaskApp
|
||||
|
||||
app = FlaskApp(__name__)
|
||||
|
||||
app.add_middleware(MiddlewareClass, **options)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :code:`add_middleware` method
|
||||
:icon: eye
|
||||
|
||||
.. automethod:: connexion.FlaskApp.add_middleware
|
||||
:noindex:
|
||||
|
||||
.. tab-item:: ConnexionMiddleware
|
||||
:sync: ConnexionMiddleware
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from asgi_framework import App
|
||||
from connexion import ConnexionMiddleware
|
||||
|
||||
app = App(__name__)
|
||||
app = ConnexionMiddleware(app)
|
||||
|
||||
app.add_middleware(MiddlewareClass, **options)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :code:`add_middleware` method
|
||||
:icon: eye
|
||||
|
||||
.. automethod:: connexion.ConnexionMiddleware.add_middleware
|
||||
:noindex:
|
||||
|
||||
Middleware order
|
||||
****************
|
||||
|
||||
The :code:`add_middleware` method takes a :code:`position` argument to define where in the
|
||||
middleware stack it should be inserted, which should be an instance of the
|
||||
:class:`~connexion.middleware.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.
|
||||
|
||||
.. autoclass:: connexion.middleware.MiddlewarePosition
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
||||
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 :class:`SecurityMiddleware` since you are handling
|
||||
Security through an API Gateway in front of your application, you can do:
|
||||
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: AsyncApp
|
||||
:sync: AsyncApp
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from connexion import AsyncApp, ConnexionMiddleware
|
||||
|
||||
middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
|
||||
if not isinstance(middleware, SecurityMiddleware)]
|
||||
|
||||
app = AsyncApp(__name__, middlewares=middlewares)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :class:`~connexion.AsyncApp`
|
||||
:code:`__init__` method
|
||||
:icon: eye
|
||||
|
||||
.. autoclass:: connexion.AsyncApp
|
||||
:noindex:
|
||||
|
||||
.. tab-item:: FlaskApp
|
||||
:sync: FlaskApp
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from connexion import FlaskApp, ConnexionMiddleware
|
||||
|
||||
middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
|
||||
if not isinstance(middleware, SecurityMiddleware)]
|
||||
|
||||
app = FlaskApp(__name__, middlewares=middlewares)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :class:`~connexion.FlaskApp`
|
||||
:code:`__init__` method
|
||||
:icon: eye
|
||||
|
||||
.. autoclass:: connexion.FlaskApp
|
||||
:noindex:
|
||||
|
||||
|
||||
.. tab-item:: ConnexionMiddleware
|
||||
:sync: ConnexionMiddleware
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from asgi_framework import App
|
||||
from connexion import ConnexionMiddleware
|
||||
|
||||
middlewares = [middleware for middleware in ConnexionMiddleware.default_middlewares
|
||||
if not isinstance(middleware, SecurityMiddleware)]
|
||||
|
||||
app = App(__name__)
|
||||
app = ConnexionMiddleware(app, middlewares=middlewares)
|
||||
|
||||
.. dropdown:: View a detailed reference of the :class:`~connexion.ConnexionMiddleware`
|
||||
:code:`__init__` method
|
||||
:icon: eye
|
||||
|
||||
.. autoclass:: connexion.ConnexionMiddleware
|
||||
:noindex:
|
||||
|
||||
|
||||
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:
|
||||
|
||||
* `CORSMiddleware`_
|
||||
* `SessionMiddleware`_
|
||||
* `HTTPSRedirectMiddleware`_
|
||||
* `TrustedHostMiddleware`_
|
||||
* `GZipMiddleware`_
|
||||
|
||||
Other useful middleware:
|
||||
|
||||
* `ProxyHeadersMiddleware`_ by Uvicorn
|
||||
* `SentryASGIMiddleware`_ by Sentry
|
||||
* `MetricsMiddleware`_ by Prometheus
|
||||
|
||||
For more, check the `asgi-middleware topic`_ on github.
|
||||
|
||||
.. _documentation of starlette: https://www.starlette.io/middleware/#writing-pure-asgi-middleware
|
||||
.. _CORSMiddleware: https://www.starlette.io/middleware/#corsmiddleware
|
||||
.. _SessionMiddleware: https://www.starlette.io/middleware/#sessionmiddleware
|
||||
.. _HTTPSRedirectMiddleware: https://www.starlette.io/middleware/#httpsredirectmiddleware
|
||||
.. _TrustedHostMiddleware: https://www.starlette.io/middleware/#trustedhostmiddleware
|
||||
.. _GZipMiddleware: https://www.starlette.io/middleware/#gzipmiddleware
|
||||
.. _ProxyHeadersMiddleware: https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py
|
||||
.. _SentryASGIMiddleware: https://docs.sentry.io/platforms/python/configuration/integrations/asgi/
|
||||
.. _MetricsMiddleware: https://github.com/claws/aioprometheus/blob/master/src/aioprometheus/asgi/middleware.py
|
||||
.. _asgi-middleware topic: https://github.com/topics/asgi-middleware
|
||||
Reference in New Issue
Block a user