I want to load my custom javascript file or code to the FastAPI Swagger UI webpage, to add some dynamic interaction when I create a FastAPI object.
For example, in Swagger UI on docs webpage I would like to
<script src="custom_script.js"></script>
or
<script> alert('worked!') </script>
I tried:
api = FastAPI(docs_url=None)
api.mount("/static", StaticFiles(directory="static"), name="static")
@api.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=api.openapi_url,
title=api.title + " - Swagger UI",
oauth2_redirect_url=api.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/sample.js",
swagger_css_url="/static/sample.css",
)
but it is not working. Is there a way just to insert my custom javascript code on docs webpage of FastAPI Swagger UI with Python ?
If you take a look at the get_swagger_ui_html
function that is imported from fastapi.openapi.docs
, you will see that the HTML for the docs page is constructed manually via string interpolation/concatenation. It would be trivial to modify this function to include an additional script element, as shown below:
# custom_swagger.py
import json
from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from fastapi.openapi.docs import swagger_ui_default_parameters
from starlette.responses import HTMLResponse
def get_swagger_ui_html(
*,
openapi_url: str,
title: str,
swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js",
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css",
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Optional[str] = None,
init_oauth: Optional[Dict[str, Any]] = None,
swagger_ui_parameters: Optional[Dict[str, Any]] = None,
custom_js_url: Optional[str] = None,
) -> HTMLResponse:
current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
if swagger_ui_parameters:
current_swagger_ui_parameters.update(swagger_ui_parameters)
html = f"""
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="{swagger_css_url}">
<link rel="shortcut icon" href="{swagger_favicon_url}">
<title>{title}</title>
</head>
<body>
<div id="swagger-ui">
</div>
"""
if custom_js_url:
html += f"""
<script src="{custom_js_url}"></script>
"""
html += f"""
<script src="{swagger_js_url}"></script>
<!-- `SwaggerUIBundle` is now available on the page -->
<script>
const ui = SwaggerUIBundle({{
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:
html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
html += """
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
})"""
if init_oauth:
html += f"""
ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
"""
html += """
</script>
</body>
</html>
"""
return HTMLResponse(html)
A new, optional parameter named custom_js_url
is added:
custom_js_url: Optional[str] = None,
If a value is provided for this parameter, a script element is inserted into the DOM directly before the script element for swagger_js_url
(this is an arbitrary choice, you can change the location of the custom script element based on your needs).
if custom_js_url:
html += f"""
<script src="{custom_js_url}"></script>
"""
If no value is provided, the HTML produced is the same as the original function.
Remember to update your import statements for get_swagger_ui_html
and update your function for the /docs
endpoint as shown below:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_oauth2_redirect_html,
)
from custom_swagger import get_swagger_ui_html
import os
app = FastAPI(docs_url=None)
path_to_static = os.path.join(os.path.dirname(__file__), 'static')
app.mount("/static", StaticFiles(directory=path_to_static), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title="My API",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
# swagger_favicon_url="/static/favicon-32x32.png",
custom_js_url="/static/custom_script.js",
)
This is still a pretty hacky solution, but I think it is much cleaner and more maintainable than putting a bunch of custom javascript inside the swagger-ui-bundle.js
file.