OpenAPI Schema Customization
FastAPI automatically generates a schema for your entire API using the OpenAPI standard. This schema is a requirement for the interactive documentation provided by Swagger UI and ReDoc, and it is also the foundation for automatic client generation.
The generation process is managed by the FastAPI application class, primarily through its openapi() method and the get_openapi utility function.
The Schema Generation Process
When a client requests the OpenAPI JSON (by default at /openapi.json), FastAPI calls the app.openapi() method. This method acts as a coordinator that gathers metadata from the application instance and inspects all registered routes to build the final schema dictionary.
The openapi() Method and Caching
The FastAPI.openapi() method is designed to be efficient by caching the generated schema. The first time it is called, it generates the schema and stores it in the self.openapi_schema attribute. Subsequent calls return the cached version.
# From fastapi/applications.py
def openapi(self) -> dict[str, Any]:
if not self.openapi_schema:
self.openapi_schema = get_openapi(
title=self.title,
version=self.version,
openapi_version=self.openapi_version,
summary=self.summary,
description=self.description,
terms_of_service=self.terms_of_service,
contact=self.contact,
license_info=self.license_info,
routes=self.routes,
webhooks=self.webhooks.routes,
tags=self.openapi_tags,
servers=self.servers,
separate_input_output_schemas=self.separate_input_output_schemas,
external_docs=self.openapi_external_docs,
)
return self.openapi_schema
The get_openapi Utility
The actual construction of the OpenAPI dictionary happens in fastapi.openapi.utils.get_openapi. This function:
- Initializes the base OpenAPI structure with
infometadata. - Iterates through all
routesandwebhooks. - Extracts Pydantic models to generate JSON Schemas for request bodies and responses.
- Maps security schemes and dependencies to OpenAPI security definitions.
Customizing the Schema
There are two primary ways to customize the generated schema: using constructor arguments for basic metadata or overriding the openapi() method for deep customization.
Basic Metadata Customization
You can set standard OpenAPI fields directly when instantiating the FastAPI class. These arguments are passed to get_openapi during generation:
from fastapi import FastAPI
app = FastAPI(
title="ChimichangApp",
description="Manage your chimichangas with ease.",
version="1.0.0",
contact={
"name": "Deadpool",
"url": "http://x-force.example.com/contact/",
"email": "dp@x-force.example.com",
},
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
},
)
Overriding the openapi Method
For advanced scenarios—such as adding custom extensions like x-logo or modifying specific paths—you can replace the app.openapi method with a custom function.
When overriding, you should follow the internal pattern of checking the cache (app.openapi_schema) to avoid re-generating the schema on every request.
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
def custom_openapi():
# 1. Check if the schema is already cached
if app.openapi_schema:
return app.openapi_schema
# 2. Generate the base schema using the utility function
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
summary="This is a very custom OpenAPI schema",
description="Here's a longer description of the custom **OpenAPI** schema",
routes=app.routes,
)
# 3. Modify the schema dictionary (e.g., add a custom logo)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
# 4. Cache the result and return it
app.openapi_schema = openapi_schema
return app.openapi_schema
# Assign the custom function to the app instance
app.openapi = custom_openapi
Dynamic Schema Adjustments
While the openapi() method generates a static schema, FastAPI performs dynamic adjustments at request time within the /openapi.json route handler. This is primarily used to handle deployments behind proxies.
Root Path and Servers
If your application is running behind a proxy with a path prefix (e.g., /api/v1), the root_path parameter ensures that the OpenAPI schema correctly reflects the external URL.
In FastAPI.setup(), the route handler for openapi_url checks if a root_path is present in the request scope. If root_path_in_servers is True (the default), it dynamically prepends the root_path to the servers list in the schema before returning it to the client.
# Logic inside FastAPI.setup() in fastapi/applications.py
async def openapi(req: Request) -> JSONResponse:
root_path = req.scope.get("root_path", "").rstrip("/")
schema = self.openapi() # Calls the (potentially overridden) openapi method
if root_path and self.root_path_in_servers:
server_urls = {s.get("url") for s in schema.get("servers", [])}
if root_path not in server_urls:
schema = dict(schema)
schema["servers"] = [{"url": root_path}] + schema.get("servers", [])
return JSONResponse(schema)
OpenAPI Version "Hack"
FastAPI generates OpenAPI version 3.1.0 by default. However, some older tools may not support this version. You can manually override the version string using the openapi_version attribute on the app instance:
app = FastAPI()
app.openapi_version = "3.0.2"
This attribute is used by get_openapi to set the openapi field in the resulting JSON. Note that this only changes the version string; it does not change the structure of the generated schema to match older specifications.