Skip to main content

Path Items and Operations

In FastAPI, the structure of the OpenAPI schema is built around the concepts of Path Items and Operations. These models, defined in fastapi.openapi.models, represent the endpoints of your API and the HTTP methods available for each.

Path Items

A PathItem (found in fastapi/openapi.models) represents the set of operations available on a single URL path. It acts as a container for different HTTP methods (GET, POST, PUT, etc.) and can also hold metadata shared across all operations on that path, such as parameters or server configurations.

class PathItem(BaseModelWithConfig):
ref: str | None = Field(default=None, alias="$ref")
summary: str | None = None
description: str | None = None
get: Operation | None = None
put: Operation | None = None
post: Operation | None = None
delete: Operation | None = None
# ... other HTTP methods
servers: list[Server] | None = None
parameters: list[Parameter | Reference] | None = None

When FastAPI generates the OpenAPI schema, it iterates through the registered routes and groups them by their path to populate these PathItem objects.

Operations

An Operation describes a single HTTP method on a specific path. It is the primary holder for endpoint metadata, including security requirements, request bodies, and possible responses.

Key fields in the Operation class include:

  • tags: Used to group operations in the UI (e.g., Swagger UI).
  • summary and description: Provide human-readable information about what the endpoint does.
  • operationId: A unique identifier for the operation across the entire API.
  • responses: A mapping of HTTP status codes to Response objects.
  • callbacks: Out-of-band reviews or notifications related to the operation.

FastAPI automatically extracts this metadata from your path operation decorators. For example, the get_openapi_operation_metadata function in fastapi/openapi/utils.py handles the extraction of basic fields:

# Internal logic in fastapi/openapi/utils.py
def get_openapi_operation_metadata(
*, route: routing.APIRoute, method: str, operation_ids: set[str]
) -> dict[str, Any]:
operation: dict[str, Any] = {}
if route.tags:
operation["tags"] = route.tags
operation["summary"] = generate_operation_summary(route=route, method=method)
if route.description:
operation["description"] = route.description
operation_id = route.operation_id or route.unique_id
# ... uniqueness checks ...
operation["operationId"] = operation_id
if route.deprecated:
operation["deprecated"] = route.deprecated
return operation

Operation IDs

The operationId is a critical field for client generators. FastAPI ensures these are unique. If you do not provide an operation_id in the decorator, FastAPI generates one using the function name and path. If a duplicate is detected during schema generation, FastAPI issues a warning to prevent issues in generated clients.

The Link class allows you to describe relationships between different operations. For instance, a response from one operation might provide a value that can be used as a parameter for another operation.

class Link(BaseModelWithConfig):
operationRef: str | None = None
operationId: str | None = None
parameters: dict[str, Any | str] | None = None
requestBody: Any | str | None = None
description: str | None = None
server: Server | None = None

Links are stored within the links field of a Response object. While FastAPI doesn't automatically generate links from route definitions, you can include them in the responses argument of your path operation decorators.

Customizing Operations with openapi_extra

For advanced use cases where you need to add custom OpenAPI extensions (fields starting with x-) or override specific parts of the generated Operation object, you can use the openapi_extra parameter in any path operation decorator.

As seen in tests/test_openapi_route_extensions.py, this dictionary is merged directly into the generated operation:

@app.get("/", openapi_extra={"x-custom-extension": "value"})
def route_with_extras():
return {"message": "Hello World"}

In fastapi/openapi/utils.py, the get_openapi_path function applies these extras using deep_dict_update:

if route.openapi_extra:
deep_dict_update(operation, route.openapi_extra)

This mechanism provides a powerful escape hatch for developers who need to adhere to specific OpenAPI requirements not natively covered by FastAPI's standard decorator arguments.