Extending OpenAPI

    The current page still doesn’t have a translation for this language.

    But you can help translating it: Contributing.

    Warning

    This is a rather advanced feature. You probably can skip it.

    If you are just following the tutorial - user guide, you can probably skip this section.

    If you already know that you need to modify the generated OpenAPI schema, continue reading.

    There are some cases where you might need to modify the generated OpenAPI schema.

    In this section you will see how.

    The normal (default) process, is as follows.

    A application (instance) has an .openapi() method that is expected to return the OpenAPI schema.

    As part of the application object creation, a path operation for /openapi.json (or for whatever you set your openapi_url) is registered.

    It just returns a JSON response with the result of the application’s .openapi() method.

    By default, what the method .openapi() does is check the property .openapi_schema to see if it has contents and return them.

    If it doesn’t, it generates them using the utility function at fastapi.openapi.utils.get_openapi.

    And that function get_openapi() receives as parameters:

    • title: The OpenAPI title, shown in the docs.
    • version: The version of your API, e.g. 2.5.0.
    • openapi_version: The version of the OpenAPI specification used. By default, the latest: 3.0.2.
    • description: The description of your API.
    • routes: A list of routes, these are each of the registered path operations. They are taken from app.routes.

    Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.

    For example, let’s add .

    First, write all your FastAPI application as normally:

    Generate the OpenAPI schema

    Then, use the same utility function to generate the OpenAPI schema, inside a custom_openapi() function:

    1. from fastapi import FastAPI
    2. from fastapi.openapi.utils import get_openapi
    3. app = FastAPI()
    4. @app.get("/items/")
    5. async def read_items():
    6. return [{"name": "Foo"}]
    7. def custom_openapi():
    8. if app.openapi_schema:
    9. return app.openapi_schema
    10. openapi_schema = get_openapi(
    11. title="Custom title",
    12. version="2.5.0",
    13. description="This is a very custom OpenAPI schema",
    14. routes=app.routes,
    15. )
    16. openapi_schema["info"]["x-logo"] = {
    17. "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    18. }
    19. app.openapi_schema = openapi_schema
    20. return app.openapi_schema
    21. app.openapi = custom_openapi

    Modify the OpenAPI schema

    Now you can add the ReDoc extension, adding a custom x-logo to the info “object” in the OpenAPI schema:

    1. from fastapi import FastAPI
    2. from fastapi.openapi.utils import get_openapi
    3. app = FastAPI()
    4. @app.get("/items/")
    5. async def read_items():
    6. return [{"name": "Foo"}]
    7. def custom_openapi():
    8. if app.openapi_schema:
    9. return app.openapi_schema
    10. openapi_schema = get_openapi(
    11. title="Custom title",
    12. version="2.5.0",
    13. description="This is a very custom OpenAPI schema",
    14. routes=app.routes,
    15. )
    16. openapi_schema["info"]["x-logo"] = {
    17. "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    18. }
    19. app.openapi_schema = openapi_schema
    20. return app.openapi_schema
    21. app.openapi = custom_openapi

    Cache the OpenAPI schema

    You can use the property .openapi_schema as a “cache”, to store your generated schema.

    That way, your application won’t have to generate the schema every time a user opens your API docs.

    It will be generated only once, and then the same cached schema will be used for the next requests.

    1. from fastapi import FastAPI
    2. from fastapi.openapi.utils import get_openapi
    3. app = FastAPI()
    4. @app.get("/items/")
    5. async def read_items():
    6. return [{"name": "Foo"}]
    7. def custom_openapi():
    8. if app.openapi_schema:
    9. return app.openapi_schema
    10. openapi_schema = get_openapi(
    11. title="Custom title",
    12. version="2.5.0",
    13. description="This is a very custom OpenAPI schema",
    14. routes=app.routes,
    15. )
    16. openapi_schema["info"]["x-logo"] = {
    17. "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    18. }
    19. app.openapi_schema = openapi_schema
    20. return app.openapi_schema
    21. app.openapi = custom_openapi

    Override the method

    Now you can replace the .openapi() method with your new function.

    1. from fastapi import FastAPI
    2. from fastapi.openapi.utils import get_openapi
    3. app = FastAPI()
    4. async def read_items():
    5. return [{"name": "Foo"}]
    6. def custom_openapi():
    7. if app.openapi_schema:
    8. return app.openapi_schema
    9. openapi_schema = get_openapi(
    10. title="Custom title",
    11. version="2.5.0",
    12. description="This is a very custom OpenAPI schema",
    13. routes=app.routes,
    14. )
    15. openapi_schema["info"]["x-logo"] = {
    16. "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
    17. }
    18. app.openapi_schema = openapi_schema
    19. return app.openapi_schema
    20. app.openapi = custom_openapi

    Check it

    Once you go to http://127.0.0.1:8000/redoc you will see that you are using your custom logo (in this example, FastAPI‘s logo):

    The API docs use Swagger UI and ReDoc, and each of those need some JavaScript and CSS files.

    By default, those files are served from a CDN.

    But it’s possible to customize it, you can set a specific CDN, or serve the files yourself.

    That’s useful, for example, if you need your app to keep working even while offline, without open Internet access, or in a local network.

    Here you’ll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them.

    Let’s say your project file structure looks like this:

    1. .
    2. ├── app
    3. ├── __init__.py
    4. ├── main.py

    Now create a directory to store those static files.

    Your new file structure could look like this:

    Download the files

    Download the static files needed for the docs and put them on that static/ directory.

    You can probably right-click each link and select an option similar to Save link as....

    Swagger UI uses the files:

    And ReDoc uses the file:

    After that, your file structure could look like:

    1. .
    2. ├── app
    3. ├── __init__.py
    4. ├── main.py
    5. └── static
    6. ├── redoc.standalone.js
    7. ├── swagger-ui-bundle.js
    8. └── swagger-ui.css

    Serve the static files

    • Import StaticFiles.
    • “Mount” a StaticFiles() instance in a specific path.
    1. from fastapi import FastAPI
    2. from fastapi.openapi.docs import (
    3. get_redoc_html,
    4. get_swagger_ui_html,
    5. get_swagger_ui_oauth2_redirect_html,
    6. )
    7. from fastapi.staticfiles import StaticFiles
    8. app = FastAPI(docs_url=None, redoc_url=None)
    9. app.mount("/static", StaticFiles(directory="static"), name="static")
    10. @app.get("/docs", include_in_schema=False)
    11. async def custom_swagger_ui_html():
    12. return get_swagger_ui_html(
    13. openapi_url=app.openapi_url,
    14. title=app.title + " - Swagger UI",
    15. oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
    16. swagger_js_url="/static/swagger-ui-bundle.js",
    17. swagger_css_url="/static/swagger-ui.css",
    18. )
    19. @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
    20. async def swagger_ui_redirect():
    21. return get_swagger_ui_oauth2_redirect_html()
    22. @app.get("/redoc", include_in_schema=False)
    23. async def redoc_html():
    24. return get_redoc_html(
    25. openapi_url=app.openapi_url,
    26. title=app.title + " - ReDoc",
    27. redoc_js_url="/static/redoc.standalone.js",
    28. )
    29. @app.get("/users/{username}")
    30. async def read_user(username: str):
    31. return {"message": f"Hello {username}"}

    Test the static files

    Start your application and go to .

    You should see a very long JavaScript file for ReDoc.

    It could start with something like:

    1. /*!
    2. * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
    3. * -------------------------------------------------------------
    4. * Version: "2.0.0-rc.18"
    5. * Repo: https://github.com/Redocly/redoc
    6. */
    7. !function(e,t){"object"==typeof exports&&"object"==typeof m
    8. ...

    That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place.

    Now we can configure the app to use those static files for the docs.

    Disable the automatic docs

    The first step is to disable the automatic docs, as those use the CDN by default.

    To disable them, set their URLs to None when creating your FastAPI app:

    1. from fastapi import FastAPI
    2. from fastapi.openapi.docs import (
    3. get_redoc_html,
    4. get_swagger_ui_html,
    5. get_swagger_ui_oauth2_redirect_html,
    6. )
    7. from fastapi.staticfiles import StaticFiles
    8. app = FastAPI(docs_url=None, redoc_url=None)
    9. app.mount("/static", StaticFiles(directory="static"), name="static")
    10. @app.get("/docs", include_in_schema=False)
    11. async def custom_swagger_ui_html():
    12. return get_swagger_ui_html(
    13. openapi_url=app.openapi_url,
    14. title=app.title + " - Swagger UI",
    15. oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
    16. swagger_js_url="/static/swagger-ui-bundle.js",
    17. swagger_css_url="/static/swagger-ui.css",
    18. )
    19. @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
    20. async def swagger_ui_redirect():
    21. return get_swagger_ui_oauth2_redirect_html()
    22. @app.get("/redoc", include_in_schema=False)
    23. async def redoc_html():
    24. return get_redoc_html(
    25. openapi_url=app.openapi_url,
    26. title=app.title + " - ReDoc",
    27. redoc_js_url="/static/redoc.standalone.js",
    28. )
    29. @app.get("/users/{username}")
    30. async def read_user(username: str):
    31. return {"message": f"Hello {username}"}

    Include the custom docs

    Now you can create the path operations for the custom docs.

    You can re-use FastAPI’s internal functions to create the HTML pages for the docs, and pass them the needed arguments:

    • openapi_url: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute app.openapi_url.
    • title: the title of your API.
    • oauth2_redirect_url: you can use app.swagger_ui_oauth2_redirect_url here to use the default.
    • swagger_js_url: the URL where the HTML for your Swagger UI docs can get the JavaScript file. This is the one that your own app is now serving.
    • swagger_css_url: the URL where the HTML for your Swagger UI docs can get the CSS file. This is the one that your own app is now serving.

    And similarly for ReDoc…

    1. from fastapi import FastAPI
    2. from fastapi.openapi.docs import (
    3. get_redoc_html,
    4. get_swagger_ui_html,
    5. get_swagger_ui_oauth2_redirect_html,
    6. )
    7. from fastapi.staticfiles import StaticFiles
    8. app = FastAPI(docs_url=None, redoc_url=None)
    9. app.mount("/static", StaticFiles(directory="static"), name="static")
    10. @app.get("/docs", include_in_schema=False)
    11. async def custom_swagger_ui_html():
    12. return get_swagger_ui_html(
    13. openapi_url=app.openapi_url,
    14. title=app.title + " - Swagger UI",
    15. oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
    16. swagger_js_url="/static/swagger-ui-bundle.js",
    17. swagger_css_url="/static/swagger-ui.css",
    18. )
    19. @app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
    20. async def swagger_ui_redirect():
    21. return get_swagger_ui_oauth2_redirect_html()
    22. @app.get("/redoc", include_in_schema=False)
    23. async def redoc_html():
    24. return get_redoc_html(
    25. openapi_url=app.openapi_url,
    26. title=app.title + " - ReDoc",
    27. redoc_js_url="/static/redoc.standalone.js",
    28. )
    29. @app.get("/users/{username}")
    30. async def read_user(username: str):
    31. return {"message": f"Hello {username}"}

    Tip

    The path operation for swagger_ui_redirect is a helper for when you use OAuth2.

    Swagger UI will handle it behind the scenes for you, but it needs this “redirect” helper.

    Now, to be able to test that everything works, create a path operation:

    Test it

    Now, you should be able to disconnect your WiFi, go to your docs at http://127.0.0.1:8000/docs, and reload the page.

    And even without Internet, you would be able to see the docs for your API and interact with it.

    You can configure some extra Swagger UI parameters.

    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:

    But you can disable it by setting syntaxHighlight to False:

    1. from fastapi import FastAPI
    2. app = FastAPI(swagger_ui_parameters={"syntaxHighlight": False})
    3. @app.get("/users/{username}")
    4. async def read_user(username: str):
    5. return {"message": f"Hello {username}"}

    …and then Swagger UI won’t show the syntax highlighting anymore:

    Extending OpenAPI - 图3

    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):

    1. from fastapi import FastAPI
    2. app = FastAPI(swagger_ui_parameters={"syntaxHighlight.theme": "obsidian"})
    3. @app.get("/users/{username}")
    4. async def read_user(username: str):
    5. return {"message": f"Hello {username}"}

    That configuration would change the syntax highlighting color theme:

    Change Default Swagger UI Parameters

    FastAPI includes some default configuration parameters appropriate for most of the use cases.

    It includes these default configurations:

    1. swagger_ui_default_parameters = {
    2. "dom_id": "#swagger-ui",
    3. "layout": "BaseLayout",
    4. "deepLinking": True,
    5. "showExtensions": True,
    6. "showCommonExtensions": True,
    7. }

    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:

    1. from fastapi import FastAPI
    2. app = FastAPI(swagger_ui_parameters={"deepLinking": False})
    3. @app.get("/users/{username}")
    4. async def read_user(username: str):
    5. return {"message": f"Hello {username}"}

    Other Swagger UI Parameters

    To see all the other possible configurations you can use, read the official .

    Swagger UI also allows other configurations to be JavaScript-only objects (for example, JavaScript functions).

    FastAPI also includes these JavaScript-only presets settings:

    1. presets: [
    2. SwaggerUIBundle.presets.apis,
    3. ]

    These are JavaScript objects, not strings, so you can’t pass them from Python code directly.