Back to Blog
Python

Python FastAPI OpenAPI and Swagger Customization

python fastapi openapi and swagger customization: Learn how to customize the OpenAPI schema and Swagger UI in FastAPI: metadata, schema overrides, docs endpoints, and...

FastAPIOpenAPISwagger UIAPI DocumentationPython Web DevelopmentAPI Customization
Diagram showing FastAPI generating a customized OpenAPI schema and Swagger UI documentation interface.

Python FastAPI OpenAPI and Swagger customization is a common requirement when the automatically generated documentation needs to match internal standards or production constraints. FastAPI generates an OpenAPI schema and serves it through Swagger UI and ReDoc by default. For most projects the defaults are enough, but production APIs often need custom metadata, modified schemas, or a different documentation endpoint. This article covers the practical ways to customize OpenAPI and Swagger in a FastAPI application without breaking the automatic generation that makes FastAPI convenient.

What FastAPI Generates by Default

When you create a FastAPI instance, it sets up several defaults:

  • openapi_url defaults to /openapi.json
  • docs_url defaults to /docs (Swagger UI)
  • redoc_url defaults to /redoc (ReDoc)

The OpenAPI schema is generated from your route definitions, request/response models, and the application metadata. You can see it by visiting /openapi.json in your browser.

The default schema includes the API title, description, version, and the paths. FastAPI derives this from the title, description, and version parameters you pass to the FastAPI() constructor.

Customizing OpenAPI Metadata

The simplest customization is setting the metadata fields on the FastAPI instance. These values appear in the generated OpenAPI document and in the Swagger UI header.

from fastapi import FastAPI app = FastAPI( title="Inventory Service", description="API for managing warehouse inventory.", version="2.1.0", contact={ "name": "API Support", "email": "support@example.com", }, license_info={ "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html", }, )

The contact and license_info dictionaries are passed through to the OpenAPI schema. FastAPI also supports terms_of_service, openapi_tags, and servers parameters. These are documented in the FastAPI configuration.

Overriding the OpenAPI Schema Function

Sometimes you need to modify the generated schema beyond metadata. For example, you might want to add a custom header parameter to every operation, or change the schema version. FastAPI lets you override the openapi method on the application instance.

The default openapi method generates the schema and caches it. To customize, you can create a function that calls the original generation logic, then modifies the result.

from fastapi import FastAPI from fastapi.openapi.utils import get_openapi app = FastAPI() def custom_openapi(): if app.openapi_schema: return app.openapi_schema schema = get_openapi( title="Custom API", version="1.0.0", description="This is a custom OpenAPI schema.", routes=app.routes, ) # Add a custom global parameter to every path for path in schema["paths"].values(): for operation in path.values(): if "parameters" not in operation: operation["parameters"] = [] operation["parameters"].append({ "name": "X-Tenant-ID", "in": "header", "required": True, "schema": {"type": "string"}, }) app.openapi_schema = schema return app.openapi_schema app.openapi = custom_openapi

This function replaces the default openapi method. The first call builds the schema and caches it in app.openapi_schema. Subsequent calls return the cached schema, so the modification runs only once.

Be careful when modifying the schema in place. The get_openapi function returns a fresh dictionary, so you can safely mutate it. If you need to change the schema based on the current state of the application, you can clear the cache by setting app.openapi_schema = None.

Customizing Swagger UI Assets

Swagger UI is served from a CDN by default. FastAPI allows you to change the JavaScript and CSS files used by the UI through the swagger_ui_parameters argument. This is useful when you want to use a different theme or add a custom logo.

app = FastAPI( swagger_ui_parameters={ "dom_id": "#swagger-ui", "layout": "BaseLayout", "deepLinking": True, "persistAuthorization": True, "displayRequestDuration": True, } )

These parameters are passed directly to Swagger UI's configuration. You can also provide a custom JavaScript file by overriding the swagger_ui_parameters with a swagger_ui_js_url and swagger_ui_css_url. However, for full control over the HTML page, you need to replace the default docs endpoint.

Adding Multiple Documentation Endpoints

Some teams want separate documentation for internal and external consumers. FastAPI lets you define multiple docs routes by creating additional routes that return the same OpenAPI schema or a modified version.

from fastapi import FastAPI from fastapi.responses import HTMLResponse app = FastAPI() # Default docs @app.get("/docs", include_in_schema=False) async def custom_swagger_ui(): return HTMLResponse(...) # custom HTML # Alternative docs @app.get("/docs-internal", include_in_schema=False) async def internal_docs(): return HTMLResponse(...) # another UI

You can also disable the default docs and serve your own. Setting docs_url=None and redoc_url=None on the FastAPI constructor removes the default endpoints. Then you can define your own routes that return the OpenAPI schema or a custom HTML page.

Security and Production Considerations

Exposing interactive API documentation in production can be a security risk. The schema reveals internal route names, parameter structures, and sometimes business logic. In many organizations, the docs are disabled or restricted to authenticated users.

To disable docs entirely, set docs_url=None and redoc_url=None. You can also conditionally enable them based on an environment variable.

import os from fastapi import FastAPI app = FastAPI( docs_url="/docs" if os.getenv("ENV") == "development" else None, redoc_url="/redoc" if os.getenv("ENV") == "development" else None, )

If you need to keep docs but protect them, you can add authentication middleware that checks for a token before serving the docs routes. The OpenAPI schema itself is also served at /openapi.json; you should protect that as well if you disable the UI.

Compatibility and Maintenance Concerns

The customization approach you choose depends on your FastAPI version and the level of control you need. The get_openapi utility and the swagger_ui_parameters argument have been stable across recent FastAPI releases, but they can change in future versions. When you override app.openapi, you are taking responsibility for the schema generation, so you must keep up with FastAPI's internal changes.

A lighter alternative is to use FastAPI's openapi_tags parameter to organize routes by tag, and to set the servers parameter to define the API's base URL. These are supported without overriding the schema function.

If you only need to add a few custom fields to the schema, consider modifying the schema after generation rather than rewriting the entire generation logic. This keeps your code closer to FastAPI's defaults and reduces the risk of missing future features.

The most maintainable approach is to separate the customization logic into a dedicated module and test it against your routes. Since the schema is derived from your code, any change to routes or models will affect the schema. Your customizations should be resilient to those changes, for example by iterating over paths and operations instead of hardcoding specific route names.

python fastapi openapi and swagger customization: Practical | RYUSLOG DEV