mirror of https://github.com/tiangolo/fastapi.git
✨ Enable configuring Swagger UI parameters (#2568)
Co-authored-by: Artem Ivanov <artem@worklife.io> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
This commit is contained in:
parent
9af8cc69d5
commit
a85aa125d2
|
|
@ -233,3 +233,82 @@ Now, to be able to test that everything works, create a *path operation*:
|
||||||
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
|
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
|
||||||
|
|
||||||
And even without Internet, you would be able to see the docs for your API and interact with it.
|
And even without Internet, you would be able to see the docs for your API and interact with it.
|
||||||
|
|
||||||
|
## Configuring Swagger UI
|
||||||
|
|
||||||
|
You can configure some extra <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">Swagger UI parameters</a>.
|
||||||
|
|
||||||
|
To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function.
|
||||||
|
|
||||||
|
`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly.
|
||||||
|
|
||||||
|
FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs.
|
||||||
|
|
||||||
|
### Disable Syntax Highlighting
|
||||||
|
|
||||||
|
For example, you could disable syntax highlighting in Swagger UI.
|
||||||
|
|
||||||
|
Without changing the settings, syntax highlighting is enabled by default:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/extending-openapi/image02.png">
|
||||||
|
|
||||||
|
But you can disable it by setting `syntaxHighlight` to `False`:
|
||||||
|
|
||||||
|
```Python hl_lines="3"
|
||||||
|
{!../../../docs_src/extending_openapi/tutorial003.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
...and then Swagger UI won't show the syntax highlighting anymore:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/extending-openapi/image03.png">
|
||||||
|
|
||||||
|
### Change the Theme
|
||||||
|
|
||||||
|
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
|
||||||
|
|
||||||
|
```Python hl_lines="3"
|
||||||
|
{!../../../docs_src/extending_openapi/tutorial004.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
That configuration would change the syntax highlighting color theme:
|
||||||
|
|
||||||
|
<img src="/img/tutorial/extending-openapi/image04.png">
|
||||||
|
|
||||||
|
### Change Default Swagger UI Parameters
|
||||||
|
|
||||||
|
FastAPI includes some default configuration parameters appropriate for most of the use cases.
|
||||||
|
|
||||||
|
It includes these default configurations:
|
||||||
|
|
||||||
|
```Python
|
||||||
|
{!../../../fastapi/openapi/docs.py[ln:7-13]!}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can override any of them by setting a different value in the argument `swagger_ui_parameters`.
|
||||||
|
|
||||||
|
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
|
||||||
|
|
||||||
|
```Python hl_lines="3"
|
||||||
|
{!../../../docs_src/extending_openapi/tutorial005.py!}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other Swagger UI Parameters
|
||||||
|
|
||||||
|
To see all the other possible configurations you can use, read the official <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">docs for Swagger UI parameters</a>.
|
||||||
|
|
||||||
|
### JavaScript-only settings
|
||||||
|
|
||||||
|
Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions).
|
||||||
|
|
||||||
|
FastAPI also includes these JavaScript-only `presets` settings:
|
||||||
|
|
||||||
|
```JavaScript
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
These are **JavaScript** objects, not strings, so you can't pass them from Python code directly.
|
||||||
|
|
||||||
|
If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need.
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -0,0 +1,8 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI(swagger_ui_parameters={"syntaxHighlight": False})
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users/{username}")
|
||||||
|
async def read_user(username: str):
|
||||||
|
return {"message": f"Hello {username}"}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI(swagger_ui_parameters={"syntaxHighlight.theme": "obsidian"})
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users/{username}")
|
||||||
|
async def read_user(username: str):
|
||||||
|
return {"message": f"Hello {username}"}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI(swagger_ui_parameters={"deepLinking": False})
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/users/{username}")
|
||||||
|
async def read_user(username: str):
|
||||||
|
return {"message": f"Hello {username}"}
|
||||||
|
|
@ -65,6 +65,7 @@ class FastAPI(Starlette):
|
||||||
callbacks: Optional[List[BaseRoute]] = None,
|
callbacks: Optional[List[BaseRoute]] = None,
|
||||||
deprecated: Optional[bool] = None,
|
deprecated: Optional[bool] = None,
|
||||||
include_in_schema: bool = True,
|
include_in_schema: bool = True,
|
||||||
|
swagger_ui_parameters: Optional[Dict[str, Any]] = None,
|
||||||
**extra: Any,
|
**extra: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
self._debug: bool = debug
|
self._debug: bool = debug
|
||||||
|
|
@ -120,6 +121,7 @@ class FastAPI(Starlette):
|
||||||
self.redoc_url = redoc_url
|
self.redoc_url = redoc_url
|
||||||
self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
|
self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
|
||||||
self.swagger_ui_init_oauth = swagger_ui_init_oauth
|
self.swagger_ui_init_oauth = swagger_ui_init_oauth
|
||||||
|
self.swagger_ui_parameters = swagger_ui_parameters
|
||||||
self.extra = extra
|
self.extra = extra
|
||||||
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
|
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
|
||||||
|
|
||||||
|
|
@ -174,6 +176,7 @@ class FastAPI(Starlette):
|
||||||
title=self.title + " - Swagger UI",
|
title=self.title + " - Swagger UI",
|
||||||
oauth2_redirect_url=oauth2_redirect_url,
|
oauth2_redirect_url=oauth2_redirect_url,
|
||||||
init_oauth=self.swagger_ui_init_oauth,
|
init_oauth=self.swagger_ui_init_oauth,
|
||||||
|
swagger_ui_parameters=self.swagger_ui_parameters,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False)
|
self.add_route(self.docs_url, swagger_ui_html, include_in_schema=False)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,14 @@ from typing import Any, Dict, Optional
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
|
swagger_ui_default_parameters = {
|
||||||
|
"dom_id": "#swagger-ui",
|
||||||
|
"layout": "BaseLayout",
|
||||||
|
"deepLinking": True,
|
||||||
|
"showExtensions": True,
|
||||||
|
"showCommonExtensions": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_swagger_ui_html(
|
def get_swagger_ui_html(
|
||||||
*,
|
*,
|
||||||
|
|
@ -14,7 +22,11 @@ def get_swagger_ui_html(
|
||||||
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
||||||
oauth2_redirect_url: Optional[str] = None,
|
oauth2_redirect_url: Optional[str] = None,
|
||||||
init_oauth: Optional[Dict[str, Any]] = None,
|
init_oauth: Optional[Dict[str, Any]] = None,
|
||||||
|
swagger_ui_parameters: Optional[Dict[str, Any]] = None,
|
||||||
) -> HTMLResponse:
|
) -> HTMLResponse:
|
||||||
|
current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
|
||||||
|
if swagger_ui_parameters:
|
||||||
|
current_swagger_ui_parameters.update(swagger_ui_parameters)
|
||||||
|
|
||||||
html = f"""
|
html = f"""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -34,19 +46,17 @@ def get_swagger_ui_html(
|
||||||
url: '{openapi_url}',
|
url: '{openapi_url}',
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
for key, value in current_swagger_ui_parameters.items():
|
||||||
|
html += f"{json.dumps(key)}: {json.dumps(jsonable_encoder(value))},\n"
|
||||||
|
|
||||||
if oauth2_redirect_url:
|
if oauth2_redirect_url:
|
||||||
html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
|
html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
|
||||||
|
|
||||||
html += """
|
html += """
|
||||||
dom_id: '#swagger-ui',
|
presets: [
|
||||||
presets: [
|
|
||||||
SwaggerUIBundle.presets.apis,
|
SwaggerUIBundle.presets.apis,
|
||||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||||
],
|
],
|
||||||
layout: "BaseLayout",
|
|
||||||
deepLinking: true,
|
|
||||||
showExtensions: true,
|
|
||||||
showCommonExtensions: true
|
|
||||||
})"""
|
})"""
|
||||||
|
|
||||||
if init_oauth:
|
if init_oauth:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from docs_src.extending_openapi.tutorial003 import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_swagger_ui():
|
||||||
|
response = client.get("/docs")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert (
|
||||||
|
'"syntaxHighlight": false' in response.text
|
||||||
|
), "syntaxHighlight should be included and converted to JSON"
|
||||||
|
assert (
|
||||||
|
'"dom_id": "#swagger-ui"' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert "presets: [" in response.text, "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.presets.apis," in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"layout": "BaseLayout",' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"deepLinking": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showCommonExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_users():
|
||||||
|
response = client.get("/users/foo")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert response.json() == {"message": "Hello foo"}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from docs_src.extending_openapi.tutorial004 import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_swagger_ui():
|
||||||
|
response = client.get("/docs")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert (
|
||||||
|
'"syntaxHighlight": false' not in response.text
|
||||||
|
), "not used parameters should not be included"
|
||||||
|
assert (
|
||||||
|
'"syntaxHighlight.theme": "obsidian"' in response.text
|
||||||
|
), "parameters with middle dots should be included in a JSON compatible way"
|
||||||
|
assert (
|
||||||
|
'"dom_id": "#swagger-ui"' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert "presets: [" in response.text, "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.presets.apis," in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"layout": "BaseLayout",' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"deepLinking": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showCommonExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_users():
|
||||||
|
response = client.get("/users/foo")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert response.json() == {"message": "Hello foo"}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from docs_src.extending_openapi.tutorial005 import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_swagger_ui():
|
||||||
|
response = client.get("/docs")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert (
|
||||||
|
'"deepLinking": false,' in response.text
|
||||||
|
), "overridden configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"deepLinking": true' not in response.text
|
||||||
|
), "overridden configs should not include the old value"
|
||||||
|
assert (
|
||||||
|
'"syntaxHighlight": false' not in response.text
|
||||||
|
), "not used parameters should not be included"
|
||||||
|
assert (
|
||||||
|
'"dom_id": "#swagger-ui"' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert "presets: [" in response.text, "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.presets.apis," in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
"SwaggerUIBundle.SwaggerUIStandalonePreset" in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"layout": "BaseLayout",' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
assert (
|
||||||
|
'"showCommonExtensions": true,' in response.text
|
||||||
|
), "default configs should be preserved"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_users():
|
||||||
|
response = client.get("/users/foo")
|
||||||
|
assert response.status_code == 200, response.text
|
||||||
|
assert response.json() == {"message": "Hello foo"}
|
||||||
Loading…
Reference in New Issue