Skip to content

Reference

setup

setup(
    app,
    *,
    docs_url="/docs",
    redoc_url="/redoc",
    swagger_js_url=_SWAGGER_JS_URL,
    swagger_css_url=_SWAGGER_CSS_URL,
    swagger_favicon_url=_FAVICON_URL,
    redoc_js_url=_REDOC_JS_URL,
    redoc_favicon_url=_FAVICON_URL,
    with_google_fonts=True,
    google_fonts_css_url=_GOOGLE_FONTS_CSS_URL,
)

Wire CSP-safe Swagger UI and ReDoc routes onto a FastAPI app.

Registers replacement routes for the interactive API docs (Swagger UI) and the alternative API docs (ReDoc) that load their JavaScript/CSS from dedicated endpoints instead of FastAPI's inline <script>/<style> tags, so a Content-Security-Policy without 'unsafe-inline' can be enforced.

The app must already be created with docs_url=None/redoc_url=None, e.g. FastAPI(docs_url=None, redoc_url=None) — otherwise FastAPI's own built-in docs would shadow the routes registered here.

Read more about it in the Quick start.

Silently skips wiring a route if app.openapi_url is None — there's no OpenAPI schema for Swagger UI/ReDoc to render in that case.

An asset URL that is a path on the app (it starts with a single /, like "/static/swagger-ui-bundle.js") gets the request's ASGI root_path in front of it, the same way the docs routes do, so self-hosted assets keep working when the app is mounted under a prefix. Absolute (https://...), protocol-relative (//...) and relative URLs are used as given.

PARAMETER DESCRIPTION
app

the FastAPI app to wire the docs routes onto.

TYPE: FastAPI

docs_url

path to serve Swagger UI at, or None to skip it.

TYPE: str | None DEFAULT: '/docs'

redoc_url

path to serve ReDoc at, or None to skip it.

TYPE: str | None DEFAULT: '/redoc'

swagger_js_url

URL of the Swagger UI JavaScript bundle.

TYPE: str DEFAULT: _SWAGGER_JS_URL

swagger_css_url

URL of the Swagger UI CSS.

TYPE: str DEFAULT: _SWAGGER_CSS_URL

swagger_favicon_url

URL of the Swagger UI page's favicon.

TYPE: str DEFAULT: _FAVICON_URL

redoc_js_url

URL of the ReDoc JavaScript bundle.

TYPE: str DEFAULT: _REDOC_JS_URL

redoc_favicon_url

URL of the ReDoc page's favicon.

TYPE: str DEFAULT: _FAVICON_URL

with_google_fonts

whether the ReDoc page loads the stylesheet at google_fonts_css_url.

TYPE: bool DEFAULT: True

google_fonts_css_url

URL of the Montserrat/Roboto stylesheet for ReDoc, Google Fonts by default.

TYPE: str DEFAULT: _GOOGLE_FONTS_CSS_URL

RAISES DESCRIPTION
RuntimeError

if app.docs_url or app.redoc_url is still set.

Source code in fastapi_csp_docs/setup.py
def setup(
    app: FastAPI,
    *,
    docs_url: str | None = "/docs",
    redoc_url: str | None = "/redoc",
    swagger_js_url: str = _SWAGGER_JS_URL,
    swagger_css_url: str = _SWAGGER_CSS_URL,
    swagger_favicon_url: str = _FAVICON_URL,
    redoc_js_url: str = _REDOC_JS_URL,
    redoc_favicon_url: str = _FAVICON_URL,
    with_google_fonts: bool = True,
    google_fonts_css_url: str = _GOOGLE_FONTS_CSS_URL,
) -> None:
    """
    Wire CSP-safe Swagger UI and ReDoc routes onto a FastAPI app.

    Registers replacement routes for the interactive API docs (Swagger UI) and the
    alternative API docs (ReDoc) that load their JavaScript/CSS from dedicated endpoints
    instead of FastAPI's inline `<script>`/`<style>` tags, so a Content-Security-Policy
    without `'unsafe-inline'` can be enforced.

    The app must already be created with `docs_url=None`/`redoc_url=None`, e.g.
    `FastAPI(docs_url=None, redoc_url=None)` — otherwise FastAPI's own built-in docs
    would shadow the routes registered here.

    Read more about it in the
    [Quick start](https://fastapi-csp-docs.matblack81.com/quickstart/).

    Silently skips wiring a route if `app.openapi_url` is `None` — there's no OpenAPI
    schema for Swagger UI/ReDoc to render in that case.

    An asset URL that is a path on the app (it starts with a single `/`, like
    `"/static/swagger-ui-bundle.js"`) gets the request's ASGI `root_path` in front of it, the
    same way the docs routes do, so self-hosted assets keep working when the app is mounted
    under a prefix. Absolute (`https://...`), protocol-relative (`//...`) and relative URLs
    are used as given.

    :param app: the FastAPI app to wire the docs routes onto.
    :param docs_url: path to serve Swagger UI at, or None to skip it.
    :param redoc_url: path to serve ReDoc at, or None to skip it.
    :param swagger_js_url: URL of the Swagger UI JavaScript bundle.
    :param swagger_css_url: URL of the Swagger UI CSS.
    :param swagger_favicon_url: URL of the Swagger UI page's favicon.
    :param redoc_js_url: URL of the ReDoc JavaScript bundle.
    :param redoc_favicon_url: URL of the ReDoc page's favicon.
    :param with_google_fonts: whether the ReDoc page loads the stylesheet at
        `google_fonts_css_url`.
    :param google_fonts_css_url: URL of the Montserrat/Roboto stylesheet for ReDoc, Google
        Fonts by default.
    :raises RuntimeError: if `app.docs_url` or `app.redoc_url` is still set.
    """
    if docs_url:
        if app.docs_url:
            raise RuntimeError(
                f"fastapi_csp_docs.setup() cannot mount Swagger UI at {docs_url!r} because "
                f"the app still serves its built-in docs at {app.docs_url!r}. Create the "
                "FastAPI app with docs_url=None to disable it first, e.g. FastAPI(docs_url=None)."
            )
        if app.openapi_url:
            _setup_swagger_ui(
                app,
                docs_url,
                swagger_js_url=swagger_js_url,
                swagger_css_url=swagger_css_url,
                swagger_favicon_url=swagger_favicon_url,
            )
    if redoc_url:
        if app.redoc_url:
            raise RuntimeError(
                f"fastapi_csp_docs.setup() cannot mount ReDoc at {redoc_url!r} because "
                f"the app still serves its built-in docs at {app.redoc_url!r}. Create the "
                "FastAPI app with redoc_url=None to disable it first, e.g. FastAPI(redoc_url=None)."
            )
        if app.openapi_url:
            _setup_redoc(
                app,
                redoc_url,
                redoc_js_url=redoc_js_url,
                redoc_favicon_url=redoc_favicon_url,
                with_google_fonts=with_google_fonts,
                google_fonts_css_url=google_fonts_css_url,
            )

Default asset URLs

setup() and the content generators share these defaults:

  • swagger_js_url: https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.34.0/swagger-ui-bundle.js
  • swagger_css_url: https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.34.0/swagger-ui.css
  • redoc_js_url: https://cdn.jsdelivr.net/npm/redoc@2.5.4/bundles/redoc.standalone.js
  • swagger_favicon_url, redoc_favicon_url: https://fastapi.tiangolo.com/img/favicon.png
  • google_fonts_css_url: https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700

Content generators

setup() builds each page and its companion script or stylesheet with these functions. Call them yourself to wire the routes by hand.

get_swagger_ui_html

get_swagger_ui_html(
    *,
    title,
    swagger_js_url=_SWAGGER_JS_URL,
    swagger_css_url=_SWAGGER_CSS_URL,
    swagger_favicon_url=_FAVICON_URL,
    swagger_ui_init_script_url="/docs/swagger-initializer.js",
)

Generate and return the HTML that loads Swagger UI for the interactive API docs (normally served at /docs).

You would only call this function yourself if you needed to override some parts, for example the URLs to use to load Swagger UI's JavaScript and CSS.

Read more about it in the FastAPI docs for Configure Swagger UI.

PARAMETER DESCRIPTION
title

HTML page title.

TYPE: str

swagger_js_url

URL of the Swagger UI JavaScript bundle.

TYPE: str DEFAULT: _SWAGGER_JS_URL

swagger_css_url

URL of the Swagger UI CSS.

TYPE: str DEFAULT: _SWAGGER_CSS_URL

swagger_favicon_url

URL of the favicon.

TYPE: str DEFAULT: _FAVICON_URL

swagger_ui_init_script_url

URL of the script that initializes Swagger UI, see get_swagger_ui_init_js.

TYPE: str DEFAULT: '/docs/swagger-initializer.js'

Source code in fastapi_csp_docs/docs.py
def get_swagger_ui_html(
    *,
    title: str,
    swagger_js_url: str = _SWAGGER_JS_URL,
    swagger_css_url: str = _SWAGGER_CSS_URL,
    swagger_favicon_url: str = _FAVICON_URL,
    swagger_ui_init_script_url: str = "/docs/swagger-initializer.js",
) -> HTMLResponse:
    """
    Generate and return the HTML that loads Swagger UI for the interactive
    API docs (normally served at `/docs`).

    You would only call this function yourself if you needed to override some parts,
    for example the URLs to use to load Swagger UI's JavaScript and CSS.

    Read more about it in the
    [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/).

    :param title: HTML page title.
    :param swagger_js_url: URL of the Swagger UI JavaScript bundle.
    :param swagger_css_url: URL of the Swagger UI CSS.
    :param swagger_favicon_url: URL of the favicon.
    :param swagger_ui_init_script_url: URL of the script that initializes Swagger UI, see
        [get_swagger_ui_init_js][fastapi_csp_docs.docs.get_swagger_ui_init_js].
    """
    page = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>{html.escape(title)}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link type="text/css" rel="stylesheet" href="{html.escape(swagger_css_url)}">
    <link rel="shortcut icon" href="{html.escape(swagger_favicon_url)}">
    </head>
    <body>
    <div id="swagger-ui"></div>
    <script src="{html.escape(swagger_js_url)}" charset="UTF-8"></script>
    <!-- `SwaggerUIBundle` is now available on the page -->
    <script src="{html.escape(swagger_ui_init_script_url)}" charset="UTF-8"></script>
    </body>
    </html>
    """
    return HTMLResponse(page)

get_swagger_ui_init_js

get_swagger_ui_init_js(
    *,
    openapi_url,
    oauth2_redirect_url=None,
    init_oauth=None,
    swagger_ui_parameters=None,
)

Generate and return the response that initializes Swagger UI.

This is normally served as swagger-initializer.js, referenced from the HTML generated by get_swagger_ui_html.

You would only call this function yourself if you needed to override some parts, for example to serve the initializer script from your own endpoint.

PARAMETER DESCRIPTION
openapi_url

URL of the OpenAPI schema for Swagger UI to render.

TYPE: str

oauth2_redirect_url

URL of the OAuth2 redirect endpoint, or None to disable OAuth2 login in the UI.

TYPE: str | None DEFAULT: None

init_oauth

OAuth2 configuration passed to ui.initOAuth(), or None to skip it.

TYPE: dict[str, Any] | None DEFAULT: None

swagger_ui_parameters

extra Swagger UI parameters merged over FastAPI's defaults.

TYPE: dict[str, Any] | None DEFAULT: None

Source code in fastapi_csp_docs/docs.py
def get_swagger_ui_init_js(
    *,
    openapi_url: str,
    oauth2_redirect_url: str | None = None,
    init_oauth: dict[str, Any] | None = None,
    swagger_ui_parameters: dict[str, Any] | None = None,
) -> Response:
    """
    Generate and return the response that initializes Swagger UI.

    This is normally served as `swagger-initializer.js`, referenced from the
    HTML generated by [get_swagger_ui_html][fastapi_csp_docs.docs.get_swagger_ui_html].

    You would only call this function yourself if you needed to override some parts,
    for example to serve the initializer script from your own endpoint.

    :param openapi_url: URL of the OpenAPI schema for Swagger UI to render.
    :param oauth2_redirect_url: URL of the OAuth2 redirect endpoint, or None to disable
        OAuth2 login in the UI.
    :param init_oauth: OAuth2 configuration passed to `ui.initOAuth()`, or None to skip it.
    :param swagger_ui_parameters: extra Swagger UI parameters merged over FastAPI's defaults.
    """
    current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
    if swagger_ui_parameters:
        current_swagger_ui_parameters.update(swagger_ui_parameters)

    js = f"""
    window.onload = function() {{
    const ui = SwaggerUIBundle({{
        url: {_html_safe_json(openapi_url)},
    """

    for key, value in current_swagger_ui_parameters.items():
        js += f"{_html_safe_json(key)}: {_html_safe_json(jsonable_encoder(value))},\n"

    if oauth2_redirect_url:
        js += f"oauth2RedirectUrl: window.location.origin + {_html_safe_json(oauth2_redirect_url)},"

    js += """
    presets: [
        SwaggerUIBundle.presets.apis,
        SwaggerUIBundle.SwaggerUIStandalonePreset
        ],
    })"""

    if init_oauth:
        js += f"""
        ui.initOAuth({_html_safe_json(jsonable_encoder(init_oauth))})
        """

    js += """
    window.ui = ui;
    };
    """
    return Response(content=js, media_type="text/javascript")

get_swagger_ui_oauth2_redirect_html

get_swagger_ui_oauth2_redirect_html(
    *, oauth2_redirect_script_url="oauth2-redirect.js"
)

Generate the HTML response with the OAuth2 redirection for Swagger UI.

You would only call this function yourself if you needed to override some parts, for example the URL of the OAuth2 redirect script.

PARAMETER DESCRIPTION
oauth2_redirect_script_url

URL of the OAuth2 redirect script, see get_swagger_ui_oauth2_redirect_js.

TYPE: str DEFAULT: 'oauth2-redirect.js'

Source code in fastapi_csp_docs/docs.py
def get_swagger_ui_oauth2_redirect_html(
    *,
    oauth2_redirect_script_url: str = "oauth2-redirect.js",
) -> HTMLResponse:
    """
    Generate the HTML response with the OAuth2 redirection for Swagger UI.

    You would only call this function yourself if you needed to override some parts,
    for example the URL of the OAuth2 redirect script.

    :param oauth2_redirect_script_url: URL of the OAuth2 redirect script, see
        [get_swagger_ui_oauth2_redirect_js][fastapi_csp_docs.docs.get_swagger_ui_oauth2_redirect_js].
    """
    page = f"""
    <!doctype html>
    <html lang="en-US">
    <head>
        <title>Swagger UI: OAuth2 Redirect</title>
    </head>
    <body>
    <script src="{html.escape(oauth2_redirect_script_url)}"></script>
    </body>
    </html>
    """
    return HTMLResponse(content=page)

get_swagger_ui_oauth2_redirect_js

get_swagger_ui_oauth2_redirect_js()

Generate and return the response with the OAuth2 redirection logic for Swagger UI.

This is normally served as oauth2-redirect.js, referenced from the HTML generated by get_swagger_ui_oauth2_redirect_html.

You normally don't need to use or change this.

Source code in fastapi_csp_docs/docs.py
def get_swagger_ui_oauth2_redirect_js() -> Response:
    """
    Generate and return the response with the OAuth2 redirection logic for
    Swagger UI.

    This is normally served as `oauth2-redirect.js`, referenced from the HTML
    generated by
    [get_swagger_ui_oauth2_redirect_html][fastapi_csp_docs.docs.get_swagger_ui_oauth2_redirect_html].

    You normally don't need to use or change this.
    """
    # minified, copied from https://github.com/swagger-api/swagger-ui/blob/v5.34.0/dist/oauth2-redirect.js
    js = (
        '"use strict";function run(){var e,r,t,a=window.opener.swaggerUIRedirectOauth2,'
        "o=a.state,n=a.redirectUrl;if((t=(r=/code|token|error/.test(window.location.hash)?"
        'window.location.hash.substring(1).replace("?","&"):location.search.substring(1))'
        '.split("&")).forEach((function(e,r,t){t[r]=\'"\'+e.replace("=",\'":"\')+\'"\'})),'
        'e=(r=r?JSON.parse("{"+t.join()+"}",(function(e,r){return""===e?r:decodeURIComponent(r)}))'
        ':{}).state===o,"accessCode"!==a.auth.schema.get("flow")&&"authorizationCode"!=='
        'a.auth.schema.get("flow")&&"authorization_code"!==a.auth.schema.get("flow")||a.auth.code)'
        "a.callback({auth:a.auth,token:r,isValid:e,redirectUrl:n});else if(e||a.errCb({authId:"
        'a.auth.name,source:"auth",level:"warning",message:"Authorization may be unsafe, passed '
        "state was changed in server Passed state wasn't returned from auth server\"}),r.code)"
        "delete a.state,a.auth.code=r.code,a.callback({auth:a.auth,redirectUrl:n});else{let e;"
        'r.error&&(e="["+r.error+"]: "+(r.error_description?r.error_description+". ":"no accessCode '
        'received from the server. ")+(r.error_uri?"More info: "+r.error_uri:"")),a.errCb({authId:'
        'a.auth.name,source:"auth",level:"error",message:e||"[Authorization failed]: no accessCode '
        'received from the server"})}window.close()}"loading"!==document.readyState?run():'
        'document.addEventListener("DOMContentLoaded",(function(){run()}));'
    )
    return Response(content=js, media_type="text/javascript")

get_redoc_html

get_redoc_html(
    *,
    openapi_url,
    title,
    redoc_js_url=_REDOC_JS_URL,
    redoc_favicon_url=_FAVICON_URL,
    with_google_fonts=True,
    redoc_css_url="/redoc/redoc.css",
    google_fonts_css_url=_GOOGLE_FONTS_CSS_URL,
    disable_search=False,
)

Generate and return the HTML response that loads ReDoc for the alternative API docs (normally served at /redoc).

You would only call this function yourself if you needed to override some parts, for example the URLs to use to load ReDoc's JavaScript and CSS.

PARAMETER DESCRIPTION
openapi_url

URL of the OpenAPI schema for ReDoc to render.

TYPE: str

title

HTML page title.

TYPE: str

redoc_js_url

URL of the ReDoc JavaScript bundle.

TYPE: str DEFAULT: _REDOC_JS_URL

redoc_favicon_url

URL of the favicon.

TYPE: str DEFAULT: _FAVICON_URL

with_google_fonts

whether to load the Montserrat/Roboto fonts from Google Fonts.

TYPE: bool DEFAULT: True

redoc_css_url

URL of the CSS reset required by ReDoc, see get_redoc_css.

TYPE: str DEFAULT: '/redoc/redoc.css'

google_fonts_css_url

URL of the Google Fonts stylesheet, used only when with_google_fonts is True.

TYPE: str DEFAULT: _GOOGLE_FONTS_CSS_URL

disable_search

whether to disable ReDoc's client-side search box (and the Web Worker it runs in), see ReDoc and CSP.

TYPE: bool DEFAULT: False

Source code in fastapi_csp_docs/docs.py
def get_redoc_html(
    *,
    openapi_url: str,
    title: str,
    redoc_js_url: str = _REDOC_JS_URL,
    redoc_favicon_url: str = _FAVICON_URL,
    with_google_fonts: bool = True,
    redoc_css_url: str = "/redoc/redoc.css",
    google_fonts_css_url: str = _GOOGLE_FONTS_CSS_URL,
    disable_search: bool = False,
) -> HTMLResponse:
    """
    Generate and return the HTML response that loads ReDoc for the alternative
    API docs (normally served at `/redoc`).

    You would only call this function yourself if you needed to override some parts,
    for example the URLs to use to load ReDoc's JavaScript and CSS.

    :param openapi_url: URL of the OpenAPI schema for ReDoc to render.
    :param title: HTML page title.
    :param redoc_js_url: URL of the ReDoc JavaScript bundle.
    :param redoc_favicon_url: URL of the favicon.
    :param with_google_fonts: whether to load the Montserrat/Roboto fonts from Google Fonts.
    :param redoc_css_url: URL of the CSS reset required by ReDoc, see
        [get_redoc_css][fastapi_csp_docs.docs.get_redoc_css].
    :param google_fonts_css_url: URL of the Google Fonts stylesheet, used only when
        `with_google_fonts` is True.
    :param disable_search: whether to disable ReDoc's client-side search box (and the Web
        Worker it runs in), see
        [ReDoc and CSP](https://fastapi-csp-docs.matblack81.com/guides/redoc-csp/#web-worker).
    """
    page = f"""
    <!DOCTYPE html>
    <html>
    <head>
    <title>{html.escape(title)}</title>
    <!-- needed for adaptive design -->
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    """
    if with_google_fonts:
        page += f"""
    <link href="{html.escape(google_fonts_css_url)}" rel="stylesheet">
    """
    page += f"""
    <link rel="shortcut icon" href="{html.escape(redoc_favicon_url)}">
    <link rel="stylesheet" type="text/css" href="{html.escape(redoc_css_url)}">
    <!--
    ReDoc doesn't change outer page styles
    -->
    </head>
    <body>
    <noscript>
        ReDoc requires Javascript to function. Please enable it to browse the documentation.
    </noscript>
    <redoc spec-url="{html.escape(openapi_url)}"{' disable-search="true"' if disable_search else ""}></redoc>
    <script src="{html.escape(redoc_js_url)}"> </script>
    </body>
    </html>
    """
    return HTMLResponse(page)

get_redoc_css

get_redoc_css()

Generate and return the response with the CSS reset required by ReDoc.

This is normally served as redoc.css, referenced from the HTML generated by get_redoc_html.

You normally don't need to use or change this.

Source code in fastapi_csp_docs/docs.py
def get_redoc_css() -> Response:
    """
    Generate and return the response with the CSS reset required by ReDoc.

    This is normally served as `redoc.css`, referenced from the HTML
    generated by [get_redoc_html][fastapi_csp_docs.docs.get_redoc_html].

    You normally don't need to use or change this.
    """
    return Response(content="body{margin:0;padding:0;}", media_type="text/css")