Add swagger-ui docs and clean up swagger-ui options (#1739)

Contributes to #1531
This commit is contained in:
Robbe Sneyders
2023-10-13 20:33:22 +02:00
committed by GitHub
parent 8459c614fd
commit 415d383740
13 changed files with 189 additions and 149 deletions

View File

@@ -12,6 +12,7 @@ from starlette.types import ASGIApp, Receive, Scope, Send
from connexion.jsonifier import Jsonifier from connexion.jsonifier import Jsonifier
from connexion.middleware import ConnexionMiddleware, MiddlewarePosition, SpecMiddleware from connexion.middleware import ConnexionMiddleware, MiddlewarePosition, SpecMiddleware
from connexion.middleware.lifespan import Lifespan from connexion.middleware.lifespan import Lifespan
from connexion.options import SwaggerUIOptions
from connexion.resolver import Resolver from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser from connexion.uri_parsing import AbstractURIParser
@@ -43,7 +44,7 @@ class AbstractApp:
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,
@@ -72,8 +73,8 @@ class AbstractApp:
start. start.
:param strict_validation: When True, extra form or query parameters not defined in the :param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False. specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See :param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
:class:`options.ConnexionOptions`. configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`. :param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has :param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False. an impact on performance. Defaults to False.
@@ -128,7 +129,7 @@ class AbstractApp:
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,

View File

@@ -17,6 +17,7 @@ from connexion.jsonifier import Jsonifier
from connexion.middleware.abstract import RoutedAPI, RoutedMiddleware from connexion.middleware.abstract import RoutedAPI, RoutedMiddleware
from connexion.middleware.lifespan import Lifespan from connexion.middleware.lifespan import Lifespan
from connexion.operations import AbstractOperation from connexion.operations import AbstractOperation
from connexion.options import SwaggerUIOptions
from connexion.resolver import Resolver from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser from connexion.uri_parsing import AbstractURIParser
@@ -131,7 +132,7 @@ class AsyncApp(AbstractApp):
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,
@@ -161,8 +162,8 @@ class AsyncApp(AbstractApp):
start. start.
:param strict_validation: When True, extra form or query parameters not defined in the :param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False. specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See :param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
:class:`options.ConnexionOptions`. configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`. :param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has :param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False. an impact on performance. Defaults to False.

View File

@@ -20,6 +20,7 @@ from connexion.jsonifier import Jsonifier
from connexion.middleware.abstract import AbstractRoutingAPI, SpecMiddleware from connexion.middleware.abstract import AbstractRoutingAPI, SpecMiddleware
from connexion.middleware.lifespan import Lifespan from connexion.middleware.lifespan import Lifespan
from connexion.operations import AbstractOperation from connexion.operations import AbstractOperation
from connexion.options import SwaggerUIOptions
from connexion.problem import problem from connexion.problem import problem
from connexion.resolver import Resolver from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser from connexion.uri_parsing import AbstractURIParser
@@ -188,7 +189,7 @@ class FlaskApp(AbstractApp):
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,
@@ -221,8 +222,8 @@ class FlaskApp(AbstractApp):
start. start.
:param strict_validation: When True, extra form or query parameters not defined in the :param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False. specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See :param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
:class:`options.ConnexionOptions`. configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`. :param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has :param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False. an impact on performance. Defaults to False.

View File

@@ -8,12 +8,16 @@ import sys
from os import path from os import path
import click import click
import importlib_metadata
from clickclick import AliasedGroup from clickclick import AliasedGroup
import connexion import connexion
from connexion.mock import MockResolver from connexion.mock import MockResolver
try:
import importlib_metadata
except ImportError:
import importlib.metadata as importlib_metadata # type: ignore
logger = logging.getLogger("connexion.cli") logger = logging.getLogger("connexion.cli")
FLASK_APP = "flask" FLASK_APP = "flask"

View File

@@ -21,6 +21,7 @@ from connexion.middleware.response_validation import ResponseValidationMiddlewar
from connexion.middleware.routing import RoutingMiddleware from connexion.middleware.routing import RoutingMiddleware
from connexion.middleware.security import SecurityMiddleware from connexion.middleware.security import SecurityMiddleware
from connexion.middleware.swagger_ui import SwaggerUIMiddleware from connexion.middleware.swagger_ui import SwaggerUIMiddleware
from connexion.options import SwaggerUIOptions
from connexion.resolver import Resolver from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser from connexion.uri_parsing import AbstractURIParser
from connexion.utils import inspect_function_arguments from connexion.utils import inspect_function_arguments
@@ -51,7 +52,7 @@ class _Options:
resolver_error: t.Optional[int] = None resolver_error: t.Optional[int] = None
resolver_error_handler: t.Optional[t.Callable] = field(init=False) resolver_error_handler: t.Optional[t.Callable] = field(init=False)
strict_validation: t.Optional[bool] = False strict_validation: t.Optional[bool] = False
swagger_ui_options: t.Optional[dict] = None swagger_ui_options: t.Optional[SwaggerUIOptions] = None
uri_parser_class: t.Optional[AbstractURIParser] = None uri_parser_class: t.Optional[AbstractURIParser] = None
validate_responses: t.Optional[bool] = False validate_responses: t.Optional[bool] = False
validator_map: t.Optional[dict] = None validator_map: t.Optional[dict] = None
@@ -186,7 +187,7 @@ class ConnexionMiddleware:
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,
@@ -214,8 +215,8 @@ class ConnexionMiddleware:
start. start.
:param strict_validation: When True, extra form or query parameters not defined in the :param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False. specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See :param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
:class:`options.ConnexionOptions`. configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`. :param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has :param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False. an impact on performance. Defaults to False.
@@ -338,7 +339,7 @@ class ConnexionMiddleware:
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None, resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None, resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None, strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None, uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None, validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None, validator_map: t.Optional[dict] = None,

View File

@@ -16,7 +16,7 @@ from starlette.types import ASGIApp, Receive, Scope, Send
from connexion.jsonifier import Jsonifier from connexion.jsonifier import Jsonifier
from connexion.middleware import SpecMiddleware from connexion.middleware import SpecMiddleware
from connexion.middleware.abstract import AbstractSpecAPI from connexion.middleware.abstract import AbstractSpecAPI
from connexion.options import SwaggerUIOptions from connexion.options import SwaggerUIConfig, SwaggerUIOptions
from connexion.utils import yamldumper from connexion.utils import yamldumper
logger = logging.getLogger("connexion.middleware.swagger_ui") logger = logging.getLogger("connexion.middleware.swagger_ui")
@@ -30,13 +30,13 @@ class SwaggerUIAPI(AbstractSpecAPI):
self, self,
*args, *args,
default: ASGIApp, default: ASGIApp,
swagger_ui_options: t.Optional[dict] = None, swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
**kwargs **kwargs
): ):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.router = Router(default=default) self.router = Router(default=default)
self.options = SwaggerUIOptions( self.options = SwaggerUIConfig(
swagger_ui_options, oas_version=self.specification.version swagger_ui_options, oas_version=self.specification.version
) )
@@ -44,11 +44,11 @@ class SwaggerUIAPI(AbstractSpecAPI):
self.add_openapi_json() self.add_openapi_json()
self.add_openapi_yaml() self.add_openapi_yaml()
if self.options.openapi_console_ui_available: if self.options.swagger_ui_available:
self.add_swagger_ui() self.add_swagger_ui()
self._templates = Jinja2Templates( self._templates = Jinja2Templates(
directory=str(self.options.openapi_console_ui_from_dir) directory=str(self.options.swagger_ui_template_dir)
) )
@staticmethod @staticmethod
@@ -121,7 +121,7 @@ class SwaggerUIAPI(AbstractSpecAPI):
""" """
Adds swagger ui to {base_path}/ui/ Adds swagger ui to {base_path}/ui/
""" """
console_ui_path = self.options.openapi_console_ui_path.strip().rstrip("/") console_ui_path = self.options.swagger_ui_path.strip().rstrip("/")
logger.debug("Adding swagger-ui: %s%s/", self.base_path, console_ui_path) logger.debug("Adding swagger-ui: %s%s/", self.base_path, console_ui_path)
for path in ( for path in (
@@ -132,7 +132,7 @@ class SwaggerUIAPI(AbstractSpecAPI):
methods=["GET"], path=path, endpoint=self._get_swagger_ui_home methods=["GET"], path=path, endpoint=self._get_swagger_ui_home
) )
if self.options.openapi_console_ui_config is not None: if self.options.swagger_ui_config:
self.router.add_route( self.router.add_route(
methods=["GET"], methods=["GET"],
path=console_ui_path + "/swagger-ui-config.json", path=console_ui_path + "/swagger-ui-config.json",
@@ -155,7 +155,7 @@ class SwaggerUIAPI(AbstractSpecAPI):
# serve index.html, so we add the redirect above. # serve index.html, so we add the redirect above.
self.router.mount( self.router.mount(
path=console_ui_path, path=console_ui_path,
app=StaticFiles(directory=str(self.options.openapi_console_ui_from_dir)), app=StaticFiles(directory=str(self.options.swagger_ui_template_dir)),
name="swagger_ui_static", name="swagger_ui_static",
) )
@@ -164,9 +164,9 @@ class SwaggerUIAPI(AbstractSpecAPI):
template_variables = { template_variables = {
"request": req, "request": req,
"openapi_spec_url": (base_path + self.options.openapi_spec_path), "openapi_spec_url": (base_path + self.options.openapi_spec_path),
**self.options.openapi_console_ui_index_template_variables, **self.options.swagger_ui_template_arguments,
} }
if self.options.openapi_console_ui_config is not None: if self.options.swagger_ui_config:
template_variables["configUrl"] = "swagger-ui-config.json" template_variables["configUrl"] = "swagger-ui-config.json"
return self._templates.TemplateResponse("index.j2", template_variables) return self._templates.TemplateResponse("index.j2", template_variables)
@@ -175,7 +175,7 @@ class SwaggerUIAPI(AbstractSpecAPI):
return StarletteResponse( return StarletteResponse(
status_code=200, status_code=200,
media_type="application/json", media_type="application/json",
content=json.dumps(self.options.openapi_console_ui_config), content=json.dumps(self.options.swagger_ui_config),
) )

View File

@@ -1,14 +1,14 @@
""" """
This module defines a Connexion specific options class to pass to the Connexion App or API. This module defines a Connexion specific options class to pass to the Connexion App or API.
""" """
import dataclasses
import logging import logging
from typing import Optional # NOQA import typing as t
try: try:
from py_swagger_ui import swagger_ui_path from py_swagger_ui import swagger_ui_path as default_template_dir
except ImportError: except ImportError:
swagger_ui_path = None default_template_dir = None
NO_UI_MSG = """The swagger_ui directory could not be found. NO_UI_MSG = """The swagger_ui directory could not be found.
Please install connexion with extra install: pip install connexion[swagger-ui] Please install connexion with extra install: pip install connexion[swagger-ui]
@@ -18,131 +18,82 @@ NO_UI_MSG = """The swagger_ui directory could not be found.
logger = logging.getLogger("connexion.options") logger = logging.getLogger("connexion.options")
@dataclasses.dataclass
class SwaggerUIOptions: class SwaggerUIOptions:
"""Options to configure the Swagger UI.
:param serve_spec: Whether to serve the Swagger / OpenAPI Specification
:param spec_path: Where to serve the Swagger / OpenAPI Specification
:param swagger_ui: Whether to serve the Swagger UI
:param swagger_ui_path: Where to serve the Swagger UI
:param swagger_ui_config: Options to configure the Swagger UI. See
https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration
for an overview of the available options.
:param swagger_ui_template_dir: Directory with static files to use to serve Swagger UI
:param swagger_ui_template_arguments: Arguments passed to the Swagger UI template. Useful
when providing your own template dir with additional template arguments.
"""
serve_spec: bool = True
spec_path: t.Optional[str] = None
swagger_ui: bool = True
swagger_ui_config: dict = dataclasses.field(default_factory=dict)
swagger_ui_path: str = "/ui"
swagger_ui_template_dir: t.Optional[str] = None
swagger_ui_template_arguments: dict = dataclasses.field(default_factory=dict)
class SwaggerUIConfig:
"""Class holding swagger UI specific options.""" """Class holding swagger UI specific options."""
def __init__(self, options=None, oas_version=(2,)): def __init__(
self._options = {} self,
self.oas_version = oas_version options: t.Optional[SwaggerUIOptions] = None,
self.swagger_ui_local_path = swagger_ui_path oas_version: t.Tuple[int, ...] = (2,),
if self.oas_version >= (3, 0, 0): ):
self.openapi_spec_name = "/openapi.json" if oas_version >= (3, 0, 0):
self.spec_path = "/openapi.json"
else: else:
self.openapi_spec_name = "/swagger.json" self.spec_path = "/swagger.json"
if options: self._options = options or SwaggerUIOptions()
self._options.update(filter_values(options))
def extend(self, new_values=None):
# type: (Optional[dict]) -> SwaggerUIOptions
"""
Return a new instance of `ConnexionOptions` using as default the currently
defined options.
"""
if new_values is None:
new_values = {}
options = dict(self._options)
options.update(filter_values(new_values))
return SwaggerUIOptions(options, self.oas_version)
def as_dict(self):
return self._options
@property @property
def openapi_spec_available(self): def openapi_spec_available(self) -> bool:
# type: () -> bool """Whether to make the OpenAPI Specification available."""
""" return self._options.serve_spec
Whether to make available the OpenAPI Specification under
`openapi_spec_path`.
Default: True
"""
deprecated_option = self._options.get("swagger_json", True)
serve_spec = self._options.get("serve_spec", deprecated_option)
if "swagger_json" in self._options:
deprecation_warning = (
"The 'swagger_json' option is deprecated. "
"Please use 'serve_spec' instead"
)
logger.warning(deprecation_warning)
return serve_spec
@property @property
def openapi_console_ui_available(self): def openapi_spec_path(self) -> str:
# type: () -> bool """Path to host the Swagger UI."""
""" return self._options.spec_path or self.spec_path
Whether to make the OpenAPI Console UI available under the path
defined in `openapi_console_ui_path` option.
Default: True @property
""" def swagger_ui_available(self) -> bool:
if ( """Whether to make the Swagger UI available."""
self._options.get("swagger_ui", True) if self._options.swagger_ui and self.swagger_ui_template_dir is None:
and self.openapi_console_ui_from_dir is None
):
logger.warning(NO_UI_MSG) logger.warning(NO_UI_MSG)
return False return False
return self._options.get("swagger_ui", True) return self._options.swagger_ui
@property @property
def openapi_spec_path(self): def swagger_ui_path(self) -> str:
# type: () -> str """Path to mount the Swagger UI and make it accessible via a browser."""
""" return self._options.swagger_ui_path
Path to mount the OpenAPI Console UI and make it accessible via a browser.
Default: /openapi.json for openapi3, otherwise /swagger.json
"""
return self._options.get("openapi_spec_path", self.openapi_spec_name)
@property @property
def openapi_console_ui_path(self): def swagger_ui_template_dir(self) -> str:
# type: () -> str """Directory with static files to use to serve Swagger UI."""
""" return self._options.swagger_ui_template_dir or default_template_dir
Path to mount the OpenAPI Console UI and make it accessible via a browser.
Default: /ui
"""
return self._options.get("swagger_url", "/ui")
@property @property
def openapi_console_ui_from_dir(self): def swagger_ui_config(self) -> dict:
# type: () -> str """Options to configure the Swagger UI."""
""" return self._options.swagger_ui_config
Custom OpenAPI Console UI directory from where Connexion will serve
the static files.
Default: Connexion's vendored version of the OpenAPI Console UI.
"""
return self._options.get("swagger_path", self.swagger_ui_local_path)
@property @property
def openapi_console_ui_config(self): def swagger_ui_template_arguments(self) -> dict:
# type: () -> dict """Arguments passed to the Swagger UI template."""
""" return self._options.swagger_ui_template_arguments
Custom OpenAPI Console UI config.
Default: None
"""
return self._options.get("swagger_ui_config", None)
@property
def openapi_console_ui_index_template_variables(self):
# type: () -> dict
"""
Custom variables passed to the OpenAPI Console UI template.
Default: {}
"""
return self._options.get("swagger_ui_template_arguments", {})
def filter_values(dictionary):
# type: (dict) -> dict
"""
Remove `None` value entries in the dictionary.
:param dictionary:
:return:
"""
return {key: value for key, value in dictionary.items() if value is not None}

View File

@@ -64,8 +64,9 @@ Documentation
quickstart quickstart
middleware middleware
cli
routing routing
swagger_ui
cli
request request
response response
security security

View File

@@ -236,10 +236,12 @@ If you installed connexion using the :code:`swagger-ui` extra, a Swagger UI is a
API, providing interactive documentation. By default the UI is hosted at :code:`{base_path}/ui/` API, providing interactive documentation. By default the UI is hosted at :code:`{base_path}/ui/`
where :code:`base_path`` is the base path of the API. where :code:`base_path`` is the base path of the API.
**https://localhost:{port}/{base_path}/ui/** **https://{host}/{base_path}/ui/**
.. image:: images/swagger_ui.png .. image:: images/swagger_ui.png
Check :doc:`swagger_ui` for information on how to configure the UI.
Full App class reference Full App class reference
------------------------ ------------------------

71
docs/swagger_ui.rst Normal file
View File

@@ -0,0 +1,71 @@
The Swagger UI
==============
If you installed connexion using the :code:`swagger-ui` extra, a Swagger UI is available for each
API, providing interactive documentation. By default the UI is hosted at :code:`{base_path}/ui/`
where :code:`base_path`` is the base path of the API.
**https://{host}/{base_path}/ui/**
.. image:: images/swagger_ui.png
Configuring the Swagger UI
--------------------------
You can change this path through the ``swagger_ui_options`` argument, either whe instantiating
your application, or when adding your api:
.. tab-set::
.. tab-item:: AsyncApp
:sync: AsyncApp
.. code-block:: python
:caption: **app.py**
from connexion import AsyncApp
from connexion.options import SwaggerUIOptions
options = SwaggerUIOptions(swagger_ui_path="/docs")
app = AsyncApp(__name__, swagger_ui_options=options)
app.add_api("openapi.yaml", swagger_ui_options=options)
.. tab-item:: FlaskApp
:sync: FlaskApp
.. code-block:: python
:caption: **app.py**
from connexion import FlaskApp
from connexion.options import SwaggerUIOptions
options = SwaggerUIOptions(swagger_ui_path="/docs")
app = FlaskApp(__name__, swagger_ui_options=options)
app.add_api("openapi.yaml", swagger_ui_options=options)
.. tab-item:: ConnexionMiddleware
:sync: ConnexionMiddleware
.. code-block:: python
:caption: **app.py**
from asgi_framework import App
from connexion import ConnexionMiddleware
from connexion.options import SwaggerUIOptions
options = SwaggerUIOptions(swagger_ui_path="/docs")
app = App(__name__)
app = ConnexionMiddleware(app, swagger_ui_options=options)
app.add_api("openapi.yaml", swagger_ui_options=options):
For a description of all available options, check the :class:`.SwaggerUIOptions`
class.
.. dropdown:: View a detailed reference of the :code:`SwaggerUIOptions` class
:icon: eye
.. autoclass:: connexion.options.SwaggerUIOptions

View File

@@ -105,7 +105,9 @@ should work, connexion comes with ``uvicorn`` as an extra:
Smaller breaking changes Smaller breaking changes
------------------------ ------------------------
* The ``options`` argument has been renamed to ``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.
* The ``uri_parser_class`` is now passed to the ``App`` or its ``add_api()`` method directly * The ``uri_parser_class`` is now passed to the ``App`` or its ``add_api()`` method directly
instead of via the ``options`` argument. instead of via the ``options`` argument.
* The ``jsonifier`` is now passed to the ``App`` or its ``add_api()`` method instead of setting it * The ``jsonifier`` is now passed to the ``App`` or its ``add_api()`` method instead of setting it

View File

@@ -8,6 +8,7 @@ from connexion.exceptions import InvalidSpecification
from connexion.http_facts import METHODS from connexion.http_facts import METHODS
from connexion.json_schema import ExtendedSafeLoader from connexion.json_schema import ExtendedSafeLoader
from connexion.middleware.abstract import AbstractRoutingAPI from connexion.middleware.abstract import AbstractRoutingAPI
from connexion.options import SwaggerUIOptions
from conftest import TEST_FOLDER, build_app_from_fixture from conftest import TEST_FOLDER, build_app_from_fixture
@@ -57,7 +58,7 @@ def test_swagger_ui(simple_api_spec_dir, spec):
def test_swagger_ui_with_config(simple_api_spec_dir, spec): def test_swagger_ui_with_config(simple_api_spec_dir, spec):
swagger_ui_config = {"displayOperationId": True} swagger_ui_config = {"displayOperationId": True}
swagger_ui_options = {"swagger_ui_config": swagger_ui_config} swagger_ui_options = SwaggerUIOptions(swagger_ui_config=swagger_ui_config)
app = App( app = App(
__name__, __name__,
specification_dir=simple_api_spec_dir, specification_dir=simple_api_spec_dir,
@@ -72,7 +73,7 @@ def test_swagger_ui_with_config(simple_api_spec_dir, spec):
def test_no_swagger_ui(simple_api_spec_dir, spec): def test_no_swagger_ui(simple_api_spec_dir, spec):
swagger_ui_options = {"swagger_ui": False} swagger_ui_options = SwaggerUIOptions(swagger_ui=False)
app = App( app = App(
__name__, __name__,
specification_dir=simple_api_spec_dir, specification_dir=simple_api_spec_dir,
@@ -85,7 +86,7 @@ def test_no_swagger_ui(simple_api_spec_dir, spec):
assert swagger_ui.status_code == 404 assert swagger_ui.status_code == 404
app2 = App(__name__, specification_dir=simple_api_spec_dir) app2 = App(__name__, specification_dir=simple_api_spec_dir)
app2.add_api(spec, swagger_ui_options={"swagger_ui": False}) app2.add_api(spec, swagger_ui_options=SwaggerUIOptions(swagger_ui=False))
app2_client = app2.test_client() app2_client = app2.test_client()
swagger_ui2 = app2_client.get("/v1.0/ui/") swagger_ui2 = app2_client.get("/v1.0/ui/")
assert swagger_ui2.status_code == 404 assert swagger_ui2.status_code == 404
@@ -94,7 +95,7 @@ def test_no_swagger_ui(simple_api_spec_dir, spec):
def test_swagger_ui_config_json(simple_api_spec_dir, spec): def test_swagger_ui_config_json(simple_api_spec_dir, spec):
"""Verify the swagger-ui-config.json file is returned for swagger_ui_config option passed to app.""" """Verify the swagger-ui-config.json file is returned for swagger_ui_config option passed to app."""
swagger_ui_config = {"displayOperationId": True} swagger_ui_config = {"displayOperationId": True}
swagger_ui_options = {"swagger_ui_config": swagger_ui_config} swagger_ui_options = SwaggerUIOptions(swagger_ui_config=swagger_ui_config)
app = App( app = App(
__name__, __name__,
specification_dir=simple_api_spec_dir, specification_dir=simple_api_spec_dir,
@@ -142,7 +143,7 @@ def test_swagger_yaml_app(simple_api_spec_dir, spec):
def test_no_swagger_json_app(simple_api_spec_dir, spec): def test_no_swagger_json_app(simple_api_spec_dir, spec):
"""Verify the spec json file is not returned when set to False when creating app.""" """Verify the spec json file is not returned when set to False when creating app."""
swagger_ui_options = {"serve_spec": False} swagger_ui_options = SwaggerUIOptions(serve_spec=False)
app = App( app = App(
__name__, __name__,
specification_dir=simple_api_spec_dir, specification_dir=simple_api_spec_dir,
@@ -193,7 +194,7 @@ def test_swagger_json_api(simple_api_spec_dir, spec):
def test_no_swagger_json_api(simple_api_spec_dir, spec): def test_no_swagger_json_api(simple_api_spec_dir, spec):
"""Verify the spec json file is not returned when set to False when adding api.""" """Verify the spec json file is not returned when set to False when adding api."""
app = App(__name__, specification_dir=simple_api_spec_dir) app = App(__name__, specification_dir=simple_api_spec_dir)
app.add_api(spec, swagger_ui_options={"serve_spec": False}) app.add_api(spec, swagger_ui_options=SwaggerUIOptions(serve_spec=False))
app_client = app.test_client() app_client = app.test_client()
url = "/v1.0/{spec}".format(spec=spec.replace("yaml", "json")) url = "/v1.0/{spec}".format(spec=spec.replace("yaml", "json"))

View File

@@ -1,7 +1,6 @@
import logging import logging
from unittest.mock import MagicMock from unittest.mock import MagicMock
import importlib_metadata
import pytest import pytest
from click.testing import CliRunner from click.testing import CliRunner
from connexion.cli import main from connexion.cli import main
@@ -9,6 +8,11 @@ from connexion.exceptions import ResolverError
from conftest import FIXTURES_FOLDER from conftest import FIXTURES_FOLDER
try:
import importlib_metadata
except ImportError:
import importlib.metadata as importlib_metadata
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def mock_app_run(app_class, monkeypatch): def mock_app_run(app_class, monkeypatch):