Skip to main content

OpenAPI and Metadata

In this project, OpenAPI is not merely a documentation artifact but the central contract that defines the API's behavior, structure, and metadata. The implementation leverages the OpenAPI 3.1.0 specification to provide a machine-readable schema that powers interactive documentation interfaces like Swagger UI and ReDoc, as well as client-side code generation.

Centralized Metadata Configuration

The primary mechanism for configuring API metadata is the FastAPI class constructor in fastapi/applications.py. This design choice centralizes the "Info Object" of the OpenAPI specification, allowing developers to define the identity and legal context of the API in a single location.

Key parameters in the FastAPI constructor include:

  • title: The name of the API (defaults to "FastAPI").
  • summary: A short summary of the API.
  • description: A detailed description, which supports Markdown.
  • version: The version of the application (defaults to "0.1.0").
  • contact and license_info: Dictionaries containing contact details and licensing terms.

These parameters are passed to the get_openapi utility function in fastapi/openapi/utils.py, which constructs the final JSON schema. For example, the license_info parameter is mapped to the license field in the OpenAPI info block, supporting both URLs and SPDX identifiers.

Organizing Documentation with Tags

To prevent large APIs from becoming a monolithic list of endpoints, the project uses a tagging system. While tags can be applied directly to path operations (e.g., @app.get("/users/", tags=["users"])), the openapi_tags parameter in the FastAPI constructor allows for rich metadata and ordering of these tags.

As seen in docs_src/metadata/tutorial004_py310.py, this metadata can include descriptions and external documentation links:

from fastapi import FastAPI

tags_metadata = [
{
"name": "users",
"description": "Operations with users. The **login** logic is also here.",
},
{
"name": "items",
"description": "Manage items. So _fancy_ they have their own docs.",
"externalDocs": {
"description": "Items external docs",
"url": "https://fastapi.tiangolo.com/",
},
},
]

app = FastAPI(openapi_tags=tags_metadata)

@app.get("/users/", tags=["users"])
async def get_users():
return [{"name": "Harry"}]

This approach decouples the documentation of a category (the tag) from the individual routes that belong to it, ensuring that the UI remains organized and informative.

Environment and Server Configuration

The servers parameter allows the API to declare multiple base URLs, which is critical for APIs deployed across different environments (e.g., staging, production).

In fastapi/applications.py, the FastAPI class also manages the root_path. When an application is behind a proxy, the root_path ensures that the generated OpenAPI schema and the interactive docs use the correct base URL. By default, root_path_in_servers is True, meaning FastAPI will automatically prepend the root_path to the servers list if it is not already present.

The OpenAPI Lifecycle and Caching

The generation of the OpenAPI schema is managed by the openapi() method of the FastAPI instance. To optimize performance, the schema is generated lazily and cached in the app.openapi_schema attribute.

# 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,
# ... other metadata ...
routes=self.routes,
tags=self.openapi_tags,
servers=self.servers,
)
return self.openapi_schema

This caching mechanism means that any modifications to the application (like adding routes or changing metadata) after the first call to the /openapi.json endpoint will not be reflected in the schema unless app.openapi_schema is manually cleared.

Customizing the Schema

For advanced use cases where the standard parameters are insufficient—such as adding custom OpenAPI extensions (fields starting with x-)—the project supports overriding the app.openapi method.

A common pattern, demonstrated in docs_src/extending_openapi/tutorial001_py310.py, involves calling the original get_openapi utility and then modifying the resulting dictionary before caching it:

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
summary="This is a very custom OpenAPI schema",
description="Description with **Markdown**",
routes=app.routes,
)
# Adding a custom extension
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema

app.openapi = custom_openapi

Security and Production Constraints

In production environments, it is often desirable to hide the API documentation. This is achieved by setting openapi_url=None in the FastAPI constructor. Because the interactive documentation tools (/docs and /redoc) depend on the OpenAPI JSON, disabling the openapi_url automatically disables these endpoints as well. This is a safety feature implemented in the setup() method of fastapi/applications.py, ensuring that no metadata is leaked if the schema endpoint is suppressed.