Litestar is a powerful, flexible yet opinionated ASGI web framework specifically focused on building high-performance APIs.
—
Automatic OpenAPI 3.1 specification generation with customizable documentation, schemas, and interactive API exploration. Litestar provides comprehensive OpenAPI support with multiple documentation interfaces and extensive customization options.
Main configuration class for OpenAPI specification generation.
class OpenAPIConfig:
def __init__(
self,
*,
title: str = "Litestar API",
version: str = "1.0.0",
description: str | None = None,
summary: str | None = None,
contact: Contact | None = None,
license: License | None = None,
servers: list[Server] | None = None,
terms_of_service: str | None = None,
external_docs: ExternalDocumentation | None = None,
security: list[SecurityRequirement] | None = None,
components: Components | None = None,
tags: list[Tag] | None = None,
webhooks: dict[str, PathItem | Reference] | None = None,
openapi_controller: type[OpenAPIController] | None = None,
favicon_url: str | None = None,
root_schema_site: Literal["redoc", "swagger", "rapidoc", "stoplight"] = "redoc",
enabled_endpoints: set[str] = frozenset({"redoc", "swagger", "openapi.json", "openapi.yaml"}),
path: str = "/schema",
create_examples: bool = True,
plugins: list[OpenAPIPlugin] | None = None,
operation_id_creator: Callable[[str, str, list[str]], str] | None = None,
use_handler_docstrings: bool = False,
by_alias: bool = True,
prefer_alias: bool = False,
openapi_version: str = "3.1.0",
):
"""
OpenAPI documentation configuration.
Parameters:
- title: API title
- version: API version
- description: API description
- summary: API summary
- contact: Contact information
- license: License information
- servers: Server configurations
- terms_of_service: Terms of service URL
- external_docs: External documentation
- security: Security requirements
- components: Reusable components
- tags: API tags for grouping operations
- webhooks: Webhook definitions
- openapi_controller: Custom controller for OpenAPI endpoints
- favicon_url: Favicon URL for documentation UI
- root_schema_site: Default documentation interface
- enabled_endpoints: Enabled documentation endpoints
- path: Base path for documentation endpoints
- create_examples: Generate examples automatically
- plugins: OpenAPI generation plugins
- operation_id_creator: Custom operation ID generator
- use_handler_docstrings: Include handler docstrings in schema
- by_alias: Use field aliases in schema
- prefer_alias: Prefer aliases over original field names
- openapi_version: OpenAPI specification version
"""
@property
def openapi_schema(self) -> OpenAPI:
"""Get the generated OpenAPI schema."""
def create_openapi_schema_model(self) -> OpenAPI:
"""Create OpenAPI schema model from configuration."""Controller that provides OpenAPI documentation endpoints.
class OpenAPIController(Controller):
path: str = "/schema"
include_in_schema: bool = False
def __init__(self, owner: Router):
"""
OpenAPI documentation controller.
Parameters:
- owner: Router that owns this controller
"""
@get(
path="/openapi.json",
media_type=MediaType.JSON,
summary="OpenAPI JSON Schema",
operation_id="get_openapi_json"
)
def get_openapi_json(self) -> dict[str, Any]:
"""Return OpenAPI schema as JSON."""
@get(
path="/openapi.yaml",
media_type="application/x-yaml",
summary="OpenAPI YAML Schema",
operation_id="get_openapi_yaml"
)
def get_openapi_yaml(self) -> str:
"""Return OpenAPI schema as YAML."""
@get(
path="/redoc",
media_type=MediaType.HTML,
summary="Redoc Documentation",
operation_id="get_redoc"
)
def get_redoc(self) -> str:
"""Serve Redoc documentation interface."""
@get(
path="/swagger",
media_type=MediaType.HTML,
summary="Swagger UI",
operation_id="get_swagger_ui"
)
def get_swagger_ui(self) -> str:
"""Serve Swagger UI documentation interface."""
@get(
path="/rapidoc",
media_type=MediaType.HTML,
summary="RapiDoc Documentation",
operation_id="get_rapidoc"
)
def get_rapidoc(self) -> str:
"""Serve RapiDoc documentation interface."""
@get(
path="/stoplight",
media_type=MediaType.HTML,
summary="Stoplight Elements",
operation_id="get_stoplight"
)
def get_stoplight(self) -> str:
"""Serve Stoplight Elements documentation interface."""Classes for defining response schemas and examples.
class ResponseSpec:
def __init__(
self,
*,
description: str = "Success",
headers: dict[str, OpenAPIHeader] | None = None,
content: dict[str, OpenAPIMediaType] | None = None,
links: dict[str, OpenAPILink] | None = None,
examples: dict[str, OpenAPIExample] | None = None,
):
"""
OpenAPI response specification.
Parameters:
- description: Response description
- headers: Response headers schema
- content: Response content schema by media type
- links: Response links
- examples: Response examples
"""
def to_schema(self) -> dict[str, Any]:
"""Convert to OpenAPI response schema."""
class OpenAPIResponse:
def __init__(
self,
description: str,
*,
headers: dict[str, OpenAPIHeader] | None = None,
content: dict[str, OpenAPIMediaType] | None = None,
links: dict[str, OpenAPILink] | None = None,
):
"""OpenAPI response object."""
class OpenAPIMediaType:
def __init__(
self,
*,
schema: OpenAPISchema | None = None,
example: Any = None,
examples: dict[str, OpenAPIExample] | None = None,
encoding: dict[str, OpenAPIEncoding] | None = None,
):
"""OpenAPI media type object."""
class OpenAPIExample:
def __init__(
self,
*,
summary: str | None = None,
description: str | None = None,
value: Any = None,
external_value: str | None = None,
):
"""OpenAPI example object."""Utilities for generating OpenAPI schemas from Python types.
def create_schema_for_field_definition(
field_definition: FieldDefinition,
generate_examples: bool = True,
plugins: Sequence[OpenAPISchemaPluginProtocol] | None = None,
) -> OpenAPISchema:
"""
Create OpenAPI schema for field definition.
Parameters:
- field_definition: Field definition to create schema for
- generate_examples: Whether to generate examples
- plugins: Schema generation plugins
Returns:
OpenAPI schema object
"""
def get_openapi_type_for_complex_type(
annotation: Any,
generate_examples: bool = True,
) -> OpenAPISchema:
"""
Get OpenAPI schema for complex Python types.
Parameters:
- annotation: Type annotation
- generate_examples: Whether to generate examples
Returns:
OpenAPI schema object
"""
class OpenAPISchemaCreator:
def __init__(
self,
plugins: Sequence[OpenAPISchemaPluginProtocol] | None = None,
generate_examples: bool = True,
):
"""
OpenAPI schema creator.
Parameters:
- plugins: Schema generation plugins
- generate_examples: Whether to generate examples
"""
def create_component_schema(
self,
field_definition: FieldDefinition,
) -> tuple[OpenAPISchema, str]:
"""
Create reusable component schema.
Returns:
Tuple of (schema, component_key)
"""
def create_schema(self, field_definition: FieldDefinition) -> OpenAPISchema:
"""Create schema for field definition."""Core data structures representing OpenAPI specification elements.
class OpenAPI:
"""Root OpenAPI specification object."""
def __init__(
self,
*,
openapi: str = "3.1.0",
info: Info,
servers: list[Server] | None = None,
paths: dict[str, PathItem] | None = None,
webhooks: dict[str, PathItem | Reference] | None = None,
components: Components | None = None,
security: list[SecurityRequirement] | None = None,
tags: list[Tag] | None = None,
external_docs: ExternalDocumentation | None = None,
):
"""OpenAPI root object."""
class Info:
"""API information object."""
def __init__(
self,
*,
title: str,
version: str,
summary: str | None = None,
description: str | None = None,
terms_of_service: str | None = None,
contact: Contact | None = None,
license: License | None = None,
):
"""API info object."""
class Server:
"""Server configuration object."""
def __init__(
self,
*,
url: str,
description: str | None = None,
variables: dict[str, ServerVariable] | None = None,
):
"""Server object."""
class PathItem:
"""Path item object containing operations."""
def __init__(
self,
*,
summary: str | None = None,
description: str | None = None,
servers: list[Server] | None = None,
parameters: list[Parameter | Reference] | None = None,
get: Operation | None = None,
put: Operation | None = None,
post: Operation | None = None,
delete: Operation | None = None,
options: Operation | None = None,
head: Operation | None = None,
patch: Operation | None = None,
trace: Operation | None = None,
):
"""Path item object."""
class Operation:
"""Operation object for HTTP methods."""
def __init__(
self,
*,
tags: list[str] | None = None,
summary: str | None = None,
description: str | None = None,
external_docs: ExternalDocumentation | None = None,
operation_id: str | None = None,
parameters: list[Parameter | Reference] | None = None,
request_body: RequestBody | Reference | None = None,
responses: dict[str, Response | Reference],
callbacks: dict[str, dict[str, PathItem]] | None = None,
deprecated: bool = False,
security: list[SecurityRequirement] | None = None,
servers: list[Server] | None = None,
):
"""Operation object."""
class Components:
"""Reusable components object."""
def __init__(
self,
*,
schemas: dict[str, Schema | Reference] | None = None,
responses: dict[str, Response | Reference] | None = None,
parameters: dict[str, Parameter | Reference] | None = None,
examples: dict[str, Example | Reference] | None = None,
request_bodies: dict[str, RequestBody | Reference] | None = None,
headers: dict[str, Header | Reference] | None = None,
security_schemes: dict[str, SecurityScheme | Reference] | None = None,
links: dict[str, Link | Reference] | None = None,
callbacks: dict[str, dict[str, PathItem] | Reference] | None = None,
path_items: dict[str, PathItem | Reference] | None = None,
):
"""Components object."""from litestar import Litestar, get, post
from litestar.openapi import OpenAPIConfig
from litestar.openapi.spec import Contact, License, Server
# Basic OpenAPI configuration
openapi_config = OpenAPIConfig(
title="My API",
version="1.0.0",
description="A comprehensive API for my application",
summary="Production-ready API with full documentation",
contact=Contact(
name="API Support",
email="support@example.com",
url="https://example.com/support"
),
license=License(
name="MIT",
url="https://opensource.org/licenses/MIT"
),
servers=[
Server(
url="https://api.example.com",
description="Production server"
),
Server(
url="https://staging-api.example.com",
description="Staging server"
),
Server(
url="http://localhost:8000",
description="Development server"
)
]
)
@get("/users", summary="List Users", description="Retrieve a list of all users")
def get_users() -> list[dict]:
"""Get all users from the system."""
return [{"id": 1, "name": "Alice"}]
@post("/users", summary="Create User", description="Create a new user")
def create_user(data: dict) -> dict:
"""Create a new user with the provided data."""
return {"id": 123, **data}
app = Litestar(
route_handlers=[get_users, create_user],
openapi_config=openapi_config
)
# Documentation available at:
# /schema/redoc - Redoc interface
# /schema/swagger - Swagger UI
# /schema/openapi.json - JSON schema
# /schema/openapi.yaml - YAML schemafrom litestar.openapi import ResponseSpec
from litestar.status_codes import *
# Define custom response specifications
user_responses = {
HTTP_200_OK: ResponseSpec(
description="User retrieved successfully",
examples={
"user_example": {
"summary": "Example user",
"value": {"id": 1, "name": "Alice", "email": "alice@example.com"}
}
}
),
HTTP_404_NOT_FOUND: ResponseSpec(
description="User not found",
examples={
"not_found": {
"summary": "User not found error",
"value": {"error": "User not found", "code": 404}
}
}
),
HTTP_422_UNPROCESSABLE_ENTITY: ResponseSpec(
description="Validation error",
examples={
"validation_error": {
"summary": "Validation failed",
"value": {
"error": "Validation failed",
"details": [
{"field": "email", "message": "Invalid email format"}
]
}
}
}
)
}
@get(
"/users/{user_id:int}",
summary="Get User",
description="Retrieve a user by ID",
responses=user_responses,
tags=["Users"]
)
def get_user(user_id: int) -> dict:
"""Get a user by their ID with detailed error responses."""
if user_id == 999:
raise NotFoundException("User not found")
return {"id": user_id, "name": "Alice", "email": "alice@example.com"}from litestar.openapi.spec import Tag
# Define API tags
tags = [
Tag(
name="Users",
description="User management operations",
external_docs={
"description": "User documentation",
"url": "https://docs.example.com/users"
}
),
Tag(
name="Products",
description="Product catalog operations"
),
Tag(
name="Orders",
description="Order processing and management"
)
]
openapi_config = OpenAPIConfig(
title="E-commerce API",
version="2.0.0",
tags=tags
)
@get("/users", tags=["Users"], summary="List all users")
def list_users() -> list[dict]:
return []
@get("/products", tags=["Products"], summary="List all products")
def list_products() -> list[dict]:
return []
@post("/orders", tags=["Orders"], summary="Create new order")
def create_order(data: dict) -> dict:
return datafrom litestar.openapi.spec import SecurityScheme, SecurityRequirement
from litestar.security.jwt import JWTAuth
# JWT authentication setup
jwt_auth = JWTAuth(
token_secret="secret-key",
retrieve_user_handler=lambda token, connection: {"id": 1}
)
# Security schemes for OpenAPI
security_schemes = {
"BearerAuth": SecurityScheme(
type="http",
scheme="bearer",
bearer_format="JWT",
description="JWT token authentication"
),
"ApiKeyAuth": SecurityScheme(
type="apiKey",
in_="header",
name="X-API-Key",
description="API key authentication"
)
}
# Global security requirements
security = [
{"BearerAuth": []}, # JWT required by default
{"ApiKeyAuth": []} # Or API key
]
openapi_config = OpenAPIConfig(
title="Secure API",
version="1.0.0",
components=Components(security_schemes=security_schemes),
security=security
)
@get("/protected", summary="Protected endpoint")
def protected_endpoint() -> dict:
"""Endpoint that requires authentication."""
return {"message": "Access granted"}
@get(
"/public",
summary="Public endpoint",
security=[], # Override global security
exclude_from_auth=True
)
def public_endpoint() -> dict:
"""Public endpoint that doesn't require authentication."""
return {"message": "Public access"}
app = Litestar(
route_handlers=[protected_endpoint, public_endpoint],
openapi_config=openapi_config,
on_app_init=[jwt_auth.on_app_init]
)def create_operation_id(
route_handler_name: str,
http_method: str,
path_components: list[str]
) -> str:
"""Create custom operation IDs."""
# Convert path components to camelCase
operation_parts = []
for component in path_components:
if component.startswith("{") and component.endswith("}"):
# Parameter - convert to "By" format
param_name = component[1:-1].split(":")[0]
operation_parts.append("By" + param_name.title())
else:
# Path segment
operation_parts.append(component.title())
# Combine with HTTP method
method_name = http_method.lower()
if method_name == "get" and len(operation_parts) > 1:
method_name = "get"
elif method_name == "get":
method_name = "list"
elif method_name == "post":
method_name = "create"
elif method_name == "put":
method_name = "update"
elif method_name == "delete":
method_name = "delete"
return method_name + "".join(operation_parts)
openapi_config = OpenAPIConfig(
title="API with Custom Operation IDs",
version="1.0.0",
operation_id_creator=create_operation_id
)
# These will generate operation IDs:
# GET /users -> listUsers
# GET /users/{user_id} -> getUserByUserId
# POST /users -> createUsers
# PUT /users/{user_id} -> updateUserByUserId
# DELETE /users/{user_id} -> deleteUserByUserId
@get("/users")
def get_users() -> list[dict]:
return []
@get("/users/{user_id:int}")
def get_user(user_id: int) -> dict:
return {"id": user_id}
@post("/users")
def create_user(data: dict) -> dict:
return datafrom litestar.openapi import OpenAPIConfig
from dataclasses import dataclass
from litestar.dto import DataclassDTO
@dataclass
class User:
name: str
email: str
age: int
id: int | None = None
UserDTO = DataclassDTO[User]
openapi_config = OpenAPIConfig(
title="API with Examples",
version="1.0.0",
create_examples=True, # Auto-generate examples
use_handler_docstrings=True # Include docstrings
)
@post("/users", dto=UserDTO, return_dto=UserDTO)
def create_user(data: User) -> User:
"""
Create a new user in the system.
This endpoint creates a new user with the provided information.
The user ID will be automatically generated.
Args:
data: User information including name, email, and age
Returns:
Created user with generated ID
Raises:
ValidationException: If user data is invalid
ConflictException: If user with email already exists
"""
data.id = 123
return data
@get("/users/{user_id:int}", return_dto=UserDTO)
def get_user(user_id: int) -> User:
"""
Retrieve a specific user by ID.
Args:
user_id: The unique identifier for the user
Returns:
User information if found
Raises:
NotFoundException: If user with given ID doesn't exist
"""
return User(id=user_id, name="Alice", email="alice@example.com", age=30)# Enable multiple documentation interfaces
openapi_config = OpenAPIConfig(
title="Multi-Interface API",
version="1.0.0",
root_schema_site="redoc", # Default interface
enabled_endpoints={
"redoc", # http://localhost:8000/schema/redoc
"swagger", # http://localhost:8000/schema/swagger
"rapidoc", # http://localhost:8000/schema/rapidoc
"stoplight", # http://localhost:8000/schema/stoplight
"openapi.json", # http://localhost:8000/schema/openapi.json
"openapi.yaml" # http://localhost:8000/schema/openapi.yaml
},
path="/docs", # Change base path
favicon_url="https://example.com/favicon.ico"
)
app = Litestar(
route_handlers=[...],
openapi_config=openapi_config
)
# Available documentation:
# /docs (redirects to /docs/redoc)
# /docs/redoc - Redoc interface
# /docs/swagger - Swagger UI
# /docs/rapidoc - RapiDoc interface
# /docs/stoplight - Stoplight Elements
# /docs/openapi.json - JSON schema
# /docs/openapi.yaml - YAML schemafrom litestar.openapi import OpenAPIController
from litestar import get, Response
class CustomOpenAPIController(OpenAPIController):
path = "/api-docs"
@get("/custom", media_type="text/html")
def custom_docs(self) -> Response:
"""Custom documentation page."""
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>Custom API Documentation</title>
</head>
<body>
<h1>My API Documentation</h1>
<p>Welcome to our custom API documentation.</p>
<ul>
<li><a href="/api-docs/redoc">Redoc Interface</a></li>
<li><a href="/api-docs/swagger">Swagger UI</a></li>
<li><a href="/api-docs/openapi.json">JSON Schema</a></li>
</ul>
</body>
</html>
"""
return Response(content=html_content, media_type="text/html")
openapi_config = OpenAPIConfig(
title="Custom Controller API",
version="1.0.0",
openapi_controller=CustomOpenAPIController,
path="/api-docs"
)# OpenAPI specification types
OpenAPISchema = dict[str, Any]
SecurityRequirement = dict[str, list[str]]
Reference = dict[str, str]
# Component types
Contact = dict[str, str]
License = dict[str, str]
ExternalDocumentation = dict[str, str]
Tag = dict[str, Any]
ServerVariable = dict[str, Any]
# Schema types
Parameter = dict[str, Any]
RequestBody = dict[str, Any]
Response = dict[str, Any]
Header = dict[str, Any]
Example = dict[str, Any]
Link = dict[str, Any]
Callback = dict[str, Any]
SecurityScheme = dict[str, Any]
Encoding = dict[str, Any]
# Plugin types
OpenAPIPlugin = Any
OpenAPISchemaPluginProtocol = Protocol
# Operation ID creator type
OperationIDCreator = Callable[[str, str, list[str]], str]
# Field definition type
FieldDefinition = AnyInstall with Tessl CLI
npx tessl i tessl/pypi-litestar