mirror of
https://github.com/LukeHagar/connexion.git
synced 2025-12-07 20:37:44 +00:00
322 lines
11 KiB
ReStructuredText
322 lines
11 KiB
ReStructuredText
Connexion 3.0: API-first for all
|
|
================================
|
|
|
|
**We are excited to announce the release of Connexion 3.0!** 🎉
|
|
|
|
Connexion 3 fundamentally changes how Connexion is designed and implemented, and how it
|
|
fits into the wider Python API ecosystem. We adopted the ASGI interface, which makes Connexion both
|
|
modular and well-integrated with most modern Python API tooling.
|
|
|
|
**It brings some major changes compared to 2.X:**
|
|
|
|
* The improved ``App`` and new ``AsyncApp`` allow you to use Connexion as a stand-alone framework
|
|
|
|
* The ``App`` interface was extended so you no longer have to care about the framework used
|
|
underneath
|
|
|
|
* Connexion can now be used as middleware to supercharge any ASGI or WSGI-compatible framework
|
|
with its spec-based functionality
|
|
* Connexion is now pluggable in many dimensions:
|
|
|
|
* All Connexion functionality is pluggable by adding or removing middleware from its stack
|
|
* Validation is now pluggable by content type, solving longstanding issues regarding endpoints
|
|
with multiple content types and making it easy to add validation for additional content types
|
|
* Authentication is now pluggable by security scheme, making it easy to customize the behavior or
|
|
add support for additional security schemes.
|
|
|
|
* Aiohttp support has been dropped due to lack of ASGI support
|
|
* We spent a lot of effort on extending and improving `our documentation`_
|
|
|
|
**Read on below to discover more changes.** 👇
|
|
|
|
Or read our `in-depth blog post`_ on the redesign.
|
|
|
|
.. _in-depth blog post: https://medium.com/@robbe.sneyders/a5dc17e81ff8?source=friends_link&sk=de5a7a67ccae8a03752f5e8e1dc68d48
|
|
.. _our documentation: https://connexion.readthedocs.io/en/stable/
|
|
|
|
Getting started with Connexion 3
|
|
--------------------------------
|
|
|
|
If you're getting started with Connexion 3 for a new project, follow the
|
|
`quickstart <quickstart.md>`_. All documentation has been updated for Connexion 3.
|
|
|
|
Migrating from Connexion 2
|
|
--------------------------
|
|
|
|
The rest of this page will focus on how to migrate from Connexion 2 to Connexion 3.
|
|
|
|
This page will show examples migrating the ``connexion.FlaskApp``. However all Connexion 3 examples
|
|
should work for ``connexion.AsyncApp`` as well. If you are not relying on the underlying
|
|
Flask application, or you are coming from the old ``AiohttpApp``, we recommend migrating to the
|
|
``connexion.AsyncApp`` instead.
|
|
|
|
Running the application
|
|
'''''''''''''''''''''''
|
|
|
|
There have been 2 changes related to running the application:
|
|
|
|
- You now MUST run the Connexion application instead of the underlying Flask application.
|
|
- You should use an ASGI server instead of a WSGI server.
|
|
|
|
While the following would work on Connexion 2, it no longer works on Connexion 3:
|
|
|
|
.. code-block:: python
|
|
:caption: **hello.py**
|
|
|
|
import connexion
|
|
|
|
app = connexion.App(__name__)
|
|
flask_app = app.app
|
|
|
|
if __name__ == "__main__":
|
|
flask_app.run()
|
|
|
|
.. code-block:: bash
|
|
|
|
$ flask --app hello:flask_app
|
|
|
|
.. code-block:: bash
|
|
|
|
$ gunicorn hello:flask_app
|
|
|
|
|
|
Instead, you need to run the Connexion application using an ASGI server:
|
|
|
|
.. code-block:: python
|
|
:caption: **hello.py**
|
|
|
|
import connexion
|
|
|
|
app = connexion.App(__name__)
|
|
|
|
if __name__ == "__main__":
|
|
app.run()
|
|
|
|
.. code-block:: bash
|
|
|
|
$ uvicorn run:app
|
|
|
|
.. code-block:: bash
|
|
|
|
$ gunicorn -k uvicorn.workers.UvicornWorker run:app
|
|
|
|
.. warning::
|
|
|
|
You can wrap Connexion with the `ASGIMiddleware`_ offered by `a2wsgi`_ to run it with a WSGI
|
|
server. You will however lose the benefits offered by ASGI, and performance might be
|
|
impacted. You should only use this as a temporary workaround until you can switch to an ASGI
|
|
server.
|
|
|
|
For more information, check :ref:`Running your application <quickstart:Running your application>`.
|
|
|
|
.. _ASGIMiddleware: https://github.com/abersheeran/a2wsgi#convert-asgi-app-to-wsgi-app
|
|
.. _a2wsgi: https://github.com/abersheeran/a2wsgi
|
|
|
|
**Workers and threads**
|
|
|
|
You can still use workers as before, however you should not use threads with ASGI, since it
|
|
handles concurrency using an async event loop instead.
|
|
|
|
In the ``AsyncApp``, concurrency is completely handled by the async event loop.
|
|
|
|
The ``FlaskApp`` is more complex, since the underlying Flask app is WSGI instead of ASGI.
|
|
Concurrency in the middleware stack is handled by the async event loop, but once a request is
|
|
passed to the underlying Flask app, it is executed in a thread pool (of 10 workers) automatically.
|
|
|
|
Error handlers
|
|
``````````````
|
|
|
|
There have been 2 changes related to running the application:
|
|
|
|
- The interface of the error handlers changed, with a request now being injected as well
|
|
- The error handlers now should be registered on the Connexion App, not the underlying Flask App
|
|
|
|
Connexion 2:
|
|
|
|
.. code-block:: python
|
|
:caption: **hello.py**
|
|
|
|
import connexion
|
|
|
|
def not_found_handler(exc: Exception) -> flask.Response:
|
|
...
|
|
|
|
app = connexion.App(__name__)
|
|
flask_app = app.app
|
|
|
|
app.add_error_handler(404, not_found_handler) # either
|
|
flask_app.register_error_handler(404, not_found_handler) # or
|
|
|
|
Connexion 3:
|
|
|
|
.. code-block:: python
|
|
:caption: **hello.py**
|
|
|
|
import connexion
|
|
from connexion.lifecycle import ConnexionRequest, ConnexionResponse
|
|
|
|
def not_found_handler(request: ConnexionRequest, exc: Exception) -> ConnexionResponse:
|
|
...
|
|
|
|
app = connexion.App(__name__)
|
|
app.add_error_handler(404, not_found_handler)
|
|
|
|
You can easily generate Connexion responses adhering to the `Problem Details for HTTP APIs`_
|
|
standard by using the ``connexion.problem.problem`` module:
|
|
|
|
.. code-block:: python
|
|
|
|
from connexion.problem import problem
|
|
|
|
def not_found_handler(request: ConnexionRequest, exc: Exception) -> ConnexionResponse:
|
|
return problem(
|
|
title=http_facts.HTTP_STATUS_CODES.get(404),
|
|
detail="The resource was not found",
|
|
status=404,
|
|
)
|
|
|
|
|
|
.. dropdown:: View a detailed reference of the ``connexion.problem.problem`` function
|
|
:icon: eye
|
|
|
|
.. autofunction:: connexion.problem.problem
|
|
:noindex:
|
|
|
|
For more information, check the :doc:`exceptions` documentation.
|
|
|
|
.. _Problem Details for HTTP APIs: https://datatracker.ietf.org/doc/html/rfc7807
|
|
|
|
Flask extensions and WSGI middleware
|
|
````````````````````````````````````
|
|
|
|
Certain Flask extensions and WSGI middleware might no longer work, since some functionaity was
|
|
moved outside the scope of the Flask application. Extensions and middleware impacting the
|
|
following functionality should now be implemented as ASGI middleware instead:
|
|
|
|
- Exception handling
|
|
- Swagger UI
|
|
- Routing
|
|
- Security
|
|
- Validation
|
|
|
|
One such example is CORS support, since it impacts routing. It can no longer be added via the
|
|
``Flask-Cors`` extension. See :ref:`Connexion Cookbook: CORS <cookbook:CORS>` on how to use a
|
|
``CORSMiddleware`` instead.
|
|
|
|
See :doc:`middleware` for general documentation on ASGI middleware.
|
|
|
|
Custom validators
|
|
`````````````````
|
|
|
|
Validation is now pluggable by content type, which means that the `VALIDATOR_MAP` has been updated
|
|
to accommodate this.
|
|
|
|
You can use the ``connexion.datastructures.MediaTypeDict`` to support content type ranges.
|
|
|
|
.. code-block:: python
|
|
|
|
VALIDATOR_MAP = {
|
|
"parameter": ParameterValidator,
|
|
"body": MediaTypeDict(
|
|
{
|
|
"*/*json": JSONRequestBodyValidator,
|
|
"application/x-www-form-urlencoded": FormDataValidator,
|
|
"multipart/form-data": MultiPartFormDataValidator,
|
|
}
|
|
),
|
|
"response": MediaTypeDict(
|
|
{
|
|
"*/*json": JSONResponseBodyValidator,
|
|
"text/plain": TextResponseBodyValidator,
|
|
}
|
|
),
|
|
}
|
|
|
|
You can pass it either to the app, or when registering an API.
|
|
|
|
.. code-block:: python
|
|
|
|
app = connexion.App(__name__, validator_map=VALIDATOR_MAP)
|
|
app.add_api("openapi.yaml", validator_map=VALIDATOR_MAP)
|
|
|
|
An ``AbstractRequestBodyValidator`` and ``AbstractResponseBodyValidator`` class are available to
|
|
support the creation of custom validators.
|
|
|
|
Swagger UI Options
|
|
------------------
|
|
|
|
The ``options`` argument has been renamed to ``swagger_ui_options`` and now takes an instance
|
|
of the :class:`.SwaggerUIOptions`. The naming of the options themselves have been changed to
|
|
better represent their meaning.
|
|
|
|
.. code-block:: python
|
|
|
|
import connexion
|
|
from connexion.options import SwaggerUIOptions
|
|
|
|
swagger_ui_options = SwaggerUIOptions(
|
|
swagger_ui=True,
|
|
swagger_ui_path="docs",
|
|
)
|
|
|
|
app = connexion.FlaskApp(__name__, swagger_ui_options=swagger_ui_options) # either
|
|
app.add_api("openapi.yaml", swagger_ui_options=swagger_ui_options) # or
|
|
|
|
See :doc:`swagger_ui` for more information.
|
|
|
|
Smaller breaking changes
|
|
------------------------
|
|
|
|
* The ``uri_parser_class`` is now passed to the ``App`` or its ``add_api()`` method directly
|
|
instead of via the ``options`` argument.
|
|
* The ``jsonifier`` is now passed to the ``App`` or its ``add_api()`` method instead of setting it
|
|
as an attribute on the Api.
|
|
* Drop Flask 1.X support and support Flask 2.X async routes
|
|
* Drop Python 3.6 (and add Python 3.10) support
|
|
* ``connexion.request`` is now a Starlette ``Request`` instead of a Flask ``Request``
|
|
* Route priority changed. The most specific route should now be defined first in the specification.
|
|
* We no longer guess a content type for response serialization if multiple are defined in the spec.
|
|
We do take into account returned headers.
|
|
* Don't return 400 when read-only property is received
|
|
* Content type is now validated for requests and responses if defined in the spec
|
|
* The deprecated positions for ``x-body-name`` are no longer supported
|
|
* The parameter ``pass_context_arg_name`` has been removed. Context is now available as global
|
|
request-level context, or can be passed in by defining a ``context_`` parameter in your view function.
|
|
* The ``MethodViewResolver`` has been renamed to ``MethodResolver``, and a new ``MethodViewResolver``
|
|
has been added to work with Flask's ``MethodView`` specifically.
|
|
* Built-in support for uWSGI has been removed. You can re-add this functionality using a custom middleware.
|
|
* The request body is now passed through for ``GET``, ``HEAD``, ``DELETE``, ``CONNECT`` and ``OPTIONS`` methods as well.
|
|
* The signature of error handlers has changed and default Flask error handlers are now replaced
|
|
with default Connexion error handlers which work the same for ``AsyncApp`` and
|
|
``ConnexionMiddleware``.
|
|
|
|
|
|
Non-breaking changes
|
|
--------------------
|
|
|
|
* Relative and nested refs are now supported in OpenAPI / Swagger specifications
|
|
* The ``required`` keyword is now supported for requestBodies
|
|
* HTTP exceptions are now implemented as a hierarchy
|
|
* Connexion now exposes ``context``, ``operation``, ``receive``, ``scope`` as global request-level context
|
|
* Connexion now provides a ``DefaultsJSONRequestBodyValidator`` to fill in default values in received
|
|
request bodies.
|
|
|
|
Full changelog
|
|
--------------
|
|
|
|
Consult our `Github release page`_ for an overview of all changes.
|
|
|
|
.. _Github release page: https://github.com/spec-first/connexion/releases/tag/3.0.0
|
|
|
|
Feedback
|
|
--------
|
|
|
|
We would really love to hear from you, so let us know if you have any feedback or questions. We'd
|
|
like to make the migration for our users as easy and possible.
|
|
|
|
* For questions, comments, and feedback, please comment on the `discussion`_ which will be
|
|
created and pinned after the release.
|
|
* For issues, please open an issue on our `Github tracker`_
|
|
|
|
.. _discussion: https://github.com/spec-first/connexion/discussions
|
|
.. _Github tracker: https://github.com/spec-first/connexion/issues |