0
# OpenAPI Documentation
1
2
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.
3
4
## Capabilities
5
6
### OpenAPI Configuration
7
8
Main configuration class for OpenAPI specification generation.
9
10
```python { .api }
11
class OpenAPIConfig:
12
def __init__(
13
self,
14
*,
15
title: str = "Litestar API",
16
version: str = "1.0.0",
17
description: str | None = None,
18
summary: str | None = None,
19
contact: Contact | None = None,
20
license: License | None = None,
21
servers: list[Server] | None = None,
22
terms_of_service: str | None = None,
23
external_docs: ExternalDocumentation | None = None,
24
security: list[SecurityRequirement] | None = None,
25
components: Components | None = None,
26
tags: list[Tag] | None = None,
27
webhooks: dict[str, PathItem | Reference] | None = None,
28
openapi_controller: type[OpenAPIController] | None = None,
29
favicon_url: str | None = None,
30
root_schema_site: Literal["redoc", "swagger", "rapidoc", "stoplight"] = "redoc",
31
enabled_endpoints: set[str] = frozenset({"redoc", "swagger", "openapi.json", "openapi.yaml"}),
32
path: str = "/schema",
33
create_examples: bool = True,
34
plugins: list[OpenAPIPlugin] | None = None,
35
operation_id_creator: Callable[[str, str, list[str]], str] | None = None,
36
use_handler_docstrings: bool = False,
37
by_alias: bool = True,
38
prefer_alias: bool = False,
39
openapi_version: str = "3.1.0",
40
):
41
"""
42
OpenAPI documentation configuration.
43
44
Parameters:
45
- title: API title
46
- version: API version
47
- description: API description
48
- summary: API summary
49
- contact: Contact information
50
- license: License information
51
- servers: Server configurations
52
- terms_of_service: Terms of service URL
53
- external_docs: External documentation
54
- security: Security requirements
55
- components: Reusable components
56
- tags: API tags for grouping operations
57
- webhooks: Webhook definitions
58
- openapi_controller: Custom controller for OpenAPI endpoints
59
- favicon_url: Favicon URL for documentation UI
60
- root_schema_site: Default documentation interface
61
- enabled_endpoints: Enabled documentation endpoints
62
- path: Base path for documentation endpoints
63
- create_examples: Generate examples automatically
64
- plugins: OpenAPI generation plugins
65
- operation_id_creator: Custom operation ID generator
66
- use_handler_docstrings: Include handler docstrings in schema
67
- by_alias: Use field aliases in schema
68
- prefer_alias: Prefer aliases over original field names
69
- openapi_version: OpenAPI specification version
70
"""
71
72
@property
73
def openapi_schema(self) -> OpenAPI:
74
"""Get the generated OpenAPI schema."""
75
76
def create_openapi_schema_model(self) -> OpenAPI:
77
"""Create OpenAPI schema model from configuration."""
78
```
79
80
### OpenAPI Controller
81
82
Controller that provides OpenAPI documentation endpoints.
83
84
```python { .api }
85
class OpenAPIController(Controller):
86
path: str = "/schema"
87
include_in_schema: bool = False
88
89
def __init__(self, owner: Router):
90
"""
91
OpenAPI documentation controller.
92
93
Parameters:
94
- owner: Router that owns this controller
95
"""
96
97
@get(
98
path="/openapi.json",
99
media_type=MediaType.JSON,
100
summary="OpenAPI JSON Schema",
101
operation_id="get_openapi_json"
102
)
103
def get_openapi_json(self) -> dict[str, Any]:
104
"""Return OpenAPI schema as JSON."""
105
106
@get(
107
path="/openapi.yaml",
108
media_type="application/x-yaml",
109
summary="OpenAPI YAML Schema",
110
operation_id="get_openapi_yaml"
111
)
112
def get_openapi_yaml(self) -> str:
113
"""Return OpenAPI schema as YAML."""
114
115
@get(
116
path="/redoc",
117
media_type=MediaType.HTML,
118
summary="Redoc Documentation",
119
operation_id="get_redoc"
120
)
121
def get_redoc(self) -> str:
122
"""Serve Redoc documentation interface."""
123
124
@get(
125
path="/swagger",
126
media_type=MediaType.HTML,
127
summary="Swagger UI",
128
operation_id="get_swagger_ui"
129
)
130
def get_swagger_ui(self) -> str:
131
"""Serve Swagger UI documentation interface."""
132
133
@get(
134
path="/rapidoc",
135
media_type=MediaType.HTML,
136
summary="RapiDoc Documentation",
137
operation_id="get_rapidoc"
138
)
139
def get_rapidoc(self) -> str:
140
"""Serve RapiDoc documentation interface."""
141
142
@get(
143
path="/stoplight",
144
media_type=MediaType.HTML,
145
summary="Stoplight Elements",
146
operation_id="get_stoplight"
147
)
148
def get_stoplight(self) -> str:
149
"""Serve Stoplight Elements documentation interface."""
150
```
151
152
### Response Specification
153
154
Classes for defining response schemas and examples.
155
156
```python { .api }
157
class ResponseSpec:
158
def __init__(
159
self,
160
*,
161
description: str = "Success",
162
headers: dict[str, OpenAPIHeader] | None = None,
163
content: dict[str, OpenAPIMediaType] | None = None,
164
links: dict[str, OpenAPILink] | None = None,
165
examples: dict[str, OpenAPIExample] | None = None,
166
):
167
"""
168
OpenAPI response specification.
169
170
Parameters:
171
- description: Response description
172
- headers: Response headers schema
173
- content: Response content schema by media type
174
- links: Response links
175
- examples: Response examples
176
"""
177
178
def to_schema(self) -> dict[str, Any]:
179
"""Convert to OpenAPI response schema."""
180
181
class OpenAPIResponse:
182
def __init__(
183
self,
184
description: str,
185
*,
186
headers: dict[str, OpenAPIHeader] | None = None,
187
content: dict[str, OpenAPIMediaType] | None = None,
188
links: dict[str, OpenAPILink] | None = None,
189
):
190
"""OpenAPI response object."""
191
192
class OpenAPIMediaType:
193
def __init__(
194
self,
195
*,
196
schema: OpenAPISchema | None = None,
197
example: Any = None,
198
examples: dict[str, OpenAPIExample] | None = None,
199
encoding: dict[str, OpenAPIEncoding] | None = None,
200
):
201
"""OpenAPI media type object."""
202
203
class OpenAPIExample:
204
def __init__(
205
self,
206
*,
207
summary: str | None = None,
208
description: str | None = None,
209
value: Any = None,
210
external_value: str | None = None,
211
):
212
"""OpenAPI example object."""
213
```
214
215
### Schema Generation
216
217
Utilities for generating OpenAPI schemas from Python types.
218
219
```python { .api }
220
def create_schema_for_field_definition(
221
field_definition: FieldDefinition,
222
generate_examples: bool = True,
223
plugins: Sequence[OpenAPISchemaPluginProtocol] | None = None,
224
) -> OpenAPISchema:
225
"""
226
Create OpenAPI schema for field definition.
227
228
Parameters:
229
- field_definition: Field definition to create schema for
230
- generate_examples: Whether to generate examples
231
- plugins: Schema generation plugins
232
233
Returns:
234
OpenAPI schema object
235
"""
236
237
def get_openapi_type_for_complex_type(
238
annotation: Any,
239
generate_examples: bool = True,
240
) -> OpenAPISchema:
241
"""
242
Get OpenAPI schema for complex Python types.
243
244
Parameters:
245
- annotation: Type annotation
246
- generate_examples: Whether to generate examples
247
248
Returns:
249
OpenAPI schema object
250
"""
251
252
class OpenAPISchemaCreator:
253
def __init__(
254
self,
255
plugins: Sequence[OpenAPISchemaPluginProtocol] | None = None,
256
generate_examples: bool = True,
257
):
258
"""
259
OpenAPI schema creator.
260
261
Parameters:
262
- plugins: Schema generation plugins
263
- generate_examples: Whether to generate examples
264
"""
265
266
def create_component_schema(
267
self,
268
field_definition: FieldDefinition,
269
) -> tuple[OpenAPISchema, str]:
270
"""
271
Create reusable component schema.
272
273
Returns:
274
Tuple of (schema, component_key)
275
"""
276
277
def create_schema(self, field_definition: FieldDefinition) -> OpenAPISchema:
278
"""Create schema for field definition."""
279
```
280
281
### OpenAPI Data Structures
282
283
Core data structures representing OpenAPI specification elements.
284
285
```python { .api }
286
class OpenAPI:
287
"""Root OpenAPI specification object."""
288
289
def __init__(
290
self,
291
*,
292
openapi: str = "3.1.0",
293
info: Info,
294
servers: list[Server] | None = None,
295
paths: dict[str, PathItem] | None = None,
296
webhooks: dict[str, PathItem | Reference] | None = None,
297
components: Components | None = None,
298
security: list[SecurityRequirement] | None = None,
299
tags: list[Tag] | None = None,
300
external_docs: ExternalDocumentation | None = None,
301
):
302
"""OpenAPI root object."""
303
304
class Info:
305
"""API information object."""
306
307
def __init__(
308
self,
309
*,
310
title: str,
311
version: str,
312
summary: str | None = None,
313
description: str | None = None,
314
terms_of_service: str | None = None,
315
contact: Contact | None = None,
316
license: License | None = None,
317
):
318
"""API info object."""
319
320
class Server:
321
"""Server configuration object."""
322
323
def __init__(
324
self,
325
*,
326
url: str,
327
description: str | None = None,
328
variables: dict[str, ServerVariable] | None = None,
329
):
330
"""Server object."""
331
332
class PathItem:
333
"""Path item object containing operations."""
334
335
def __init__(
336
self,
337
*,
338
summary: str | None = None,
339
description: str | None = None,
340
servers: list[Server] | None = None,
341
parameters: list[Parameter | Reference] | None = None,
342
get: Operation | None = None,
343
put: Operation | None = None,
344
post: Operation | None = None,
345
delete: Operation | None = None,
346
options: Operation | None = None,
347
head: Operation | None = None,
348
patch: Operation | None = None,
349
trace: Operation | None = None,
350
):
351
"""Path item object."""
352
353
class Operation:
354
"""Operation object for HTTP methods."""
355
356
def __init__(
357
self,
358
*,
359
tags: list[str] | None = None,
360
summary: str | None = None,
361
description: str | None = None,
362
external_docs: ExternalDocumentation | None = None,
363
operation_id: str | None = None,
364
parameters: list[Parameter | Reference] | None = None,
365
request_body: RequestBody | Reference | None = None,
366
responses: dict[str, Response | Reference],
367
callbacks: dict[str, dict[str, PathItem]] | None = None,
368
deprecated: bool = False,
369
security: list[SecurityRequirement] | None = None,
370
servers: list[Server] | None = None,
371
):
372
"""Operation object."""
373
374
class Components:
375
"""Reusable components object."""
376
377
def __init__(
378
self,
379
*,
380
schemas: dict[str, Schema | Reference] | None = None,
381
responses: dict[str, Response | Reference] | None = None,
382
parameters: dict[str, Parameter | Reference] | None = None,
383
examples: dict[str, Example | Reference] | None = None,
384
request_bodies: dict[str, RequestBody | Reference] | None = None,
385
headers: dict[str, Header | Reference] | None = None,
386
security_schemes: dict[str, SecurityScheme | Reference] | None = None,
387
links: dict[str, Link | Reference] | None = None,
388
callbacks: dict[str, dict[str, PathItem] | Reference] | None = None,
389
path_items: dict[str, PathItem | Reference] | None = None,
390
):
391
"""Components object."""
392
```
393
394
## Usage Examples
395
396
### Basic OpenAPI Configuration
397
398
```python
399
from litestar import Litestar, get, post
400
from litestar.openapi import OpenAPIConfig
401
from litestar.openapi.spec import Contact, License, Server
402
403
# Basic OpenAPI configuration
404
openapi_config = OpenAPIConfig(
405
title="My API",
406
version="1.0.0",
407
description="A comprehensive API for my application",
408
summary="Production-ready API with full documentation",
409
contact=Contact(
410
name="API Support",
411
email="support@example.com",
412
url="https://example.com/support"
413
),
414
license=License(
415
name="MIT",
416
url="https://opensource.org/licenses/MIT"
417
),
418
servers=[
419
Server(
420
url="https://api.example.com",
421
description="Production server"
422
),
423
Server(
424
url="https://staging-api.example.com",
425
description="Staging server"
426
),
427
Server(
428
url="http://localhost:8000",
429
description="Development server"
430
)
431
]
432
)
433
434
@get("/users", summary="List Users", description="Retrieve a list of all users")
435
def get_users() -> list[dict]:
436
"""Get all users from the system."""
437
return [{"id": 1, "name": "Alice"}]
438
439
@post("/users", summary="Create User", description="Create a new user")
440
def create_user(data: dict) -> dict:
441
"""Create a new user with the provided data."""
442
return {"id": 123, **data}
443
444
app = Litestar(
445
route_handlers=[get_users, create_user],
446
openapi_config=openapi_config
447
)
448
449
# Documentation available at:
450
# /schema/redoc - Redoc interface
451
# /schema/swagger - Swagger UI
452
# /schema/openapi.json - JSON schema
453
# /schema/openapi.yaml - YAML schema
454
```
455
456
### Custom Response Specifications
457
458
```python
459
from litestar.openapi import ResponseSpec
460
from litestar.status_codes import *
461
462
# Define custom response specifications
463
user_responses = {
464
HTTP_200_OK: ResponseSpec(
465
description="User retrieved successfully",
466
examples={
467
"user_example": {
468
"summary": "Example user",
469
"value": {"id": 1, "name": "Alice", "email": "alice@example.com"}
470
}
471
}
472
),
473
HTTP_404_NOT_FOUND: ResponseSpec(
474
description="User not found",
475
examples={
476
"not_found": {
477
"summary": "User not found error",
478
"value": {"error": "User not found", "code": 404}
479
}
480
}
481
),
482
HTTP_422_UNPROCESSABLE_ENTITY: ResponseSpec(
483
description="Validation error",
484
examples={
485
"validation_error": {
486
"summary": "Validation failed",
487
"value": {
488
"error": "Validation failed",
489
"details": [
490
{"field": "email", "message": "Invalid email format"}
491
]
492
}
493
}
494
}
495
)
496
}
497
498
@get(
499
"/users/{user_id:int}",
500
summary="Get User",
501
description="Retrieve a user by ID",
502
responses=user_responses,
503
tags=["Users"]
504
)
505
def get_user(user_id: int) -> dict:
506
"""Get a user by their ID with detailed error responses."""
507
if user_id == 999:
508
raise NotFoundException("User not found")
509
return {"id": user_id, "name": "Alice", "email": "alice@example.com"}
510
```
511
512
### API Tags and Organization
513
514
```python
515
from litestar.openapi.spec import Tag
516
517
# Define API tags
518
tags = [
519
Tag(
520
name="Users",
521
description="User management operations",
522
external_docs={
523
"description": "User documentation",
524
"url": "https://docs.example.com/users"
525
}
526
),
527
Tag(
528
name="Products",
529
description="Product catalog operations"
530
),
531
Tag(
532
name="Orders",
533
description="Order processing and management"
534
)
535
]
536
537
openapi_config = OpenAPIConfig(
538
title="E-commerce API",
539
version="2.0.0",
540
tags=tags
541
)
542
543
@get("/users", tags=["Users"], summary="List all users")
544
def list_users() -> list[dict]:
545
return []
546
547
@get("/products", tags=["Products"], summary="List all products")
548
def list_products() -> list[dict]:
549
return []
550
551
@post("/orders", tags=["Orders"], summary="Create new order")
552
def create_order(data: dict) -> dict:
553
return data
554
```
555
556
### Security Schemes
557
558
```python
559
from litestar.openapi.spec import SecurityScheme, SecurityRequirement
560
from litestar.security.jwt import JWTAuth
561
562
# JWT authentication setup
563
jwt_auth = JWTAuth(
564
token_secret="secret-key",
565
retrieve_user_handler=lambda token, connection: {"id": 1}
566
)
567
568
# Security schemes for OpenAPI
569
security_schemes = {
570
"BearerAuth": SecurityScheme(
571
type="http",
572
scheme="bearer",
573
bearer_format="JWT",
574
description="JWT token authentication"
575
),
576
"ApiKeyAuth": SecurityScheme(
577
type="apiKey",
578
in_="header",
579
name="X-API-Key",
580
description="API key authentication"
581
)
582
}
583
584
# Global security requirements
585
security = [
586
{"BearerAuth": []}, # JWT required by default
587
{"ApiKeyAuth": []} # Or API key
588
]
589
590
openapi_config = OpenAPIConfig(
591
title="Secure API",
592
version="1.0.0",
593
components=Components(security_schemes=security_schemes),
594
security=security
595
)
596
597
@get("/protected", summary="Protected endpoint")
598
def protected_endpoint() -> dict:
599
"""Endpoint that requires authentication."""
600
return {"message": "Access granted"}
601
602
@get(
603
"/public",
604
summary="Public endpoint",
605
security=[], # Override global security
606
exclude_from_auth=True
607
)
608
def public_endpoint() -> dict:
609
"""Public endpoint that doesn't require authentication."""
610
return {"message": "Public access"}
611
612
app = Litestar(
613
route_handlers=[protected_endpoint, public_endpoint],
614
openapi_config=openapi_config,
615
on_app_init=[jwt_auth.on_app_init]
616
)
617
```
618
619
### Custom Operation IDs
620
621
```python
622
def create_operation_id(
623
route_handler_name: str,
624
http_method: str,
625
path_components: list[str]
626
) -> str:
627
"""Create custom operation IDs."""
628
# Convert path components to camelCase
629
operation_parts = []
630
631
for component in path_components:
632
if component.startswith("{") and component.endswith("}"):
633
# Parameter - convert to "By" format
634
param_name = component[1:-1].split(":")[0]
635
operation_parts.append("By" + param_name.title())
636
else:
637
# Path segment
638
operation_parts.append(component.title())
639
640
# Combine with HTTP method
641
method_name = http_method.lower()
642
if method_name == "get" and len(operation_parts) > 1:
643
method_name = "get"
644
elif method_name == "get":
645
method_name = "list"
646
elif method_name == "post":
647
method_name = "create"
648
elif method_name == "put":
649
method_name = "update"
650
elif method_name == "delete":
651
method_name = "delete"
652
653
return method_name + "".join(operation_parts)
654
655
openapi_config = OpenAPIConfig(
656
title="API with Custom Operation IDs",
657
version="1.0.0",
658
operation_id_creator=create_operation_id
659
)
660
661
# These will generate operation IDs:
662
# GET /users -> listUsers
663
# GET /users/{user_id} -> getUserByUserId
664
# POST /users -> createUsers
665
# PUT /users/{user_id} -> updateUserByUserId
666
# DELETE /users/{user_id} -> deleteUserByUserId
667
668
@get("/users")
669
def get_users() -> list[dict]:
670
return []
671
672
@get("/users/{user_id:int}")
673
def get_user(user_id: int) -> dict:
674
return {"id": user_id}
675
676
@post("/users")
677
def create_user(data: dict) -> dict:
678
return data
679
```
680
681
### Documentation with Examples
682
683
```python
684
from litestar.openapi import OpenAPIConfig
685
from dataclasses import dataclass
686
from litestar.dto import DataclassDTO
687
688
@dataclass
689
class User:
690
name: str
691
email: str
692
age: int
693
id: int | None = None
694
695
UserDTO = DataclassDTO[User]
696
697
openapi_config = OpenAPIConfig(
698
title="API with Examples",
699
version="1.0.0",
700
create_examples=True, # Auto-generate examples
701
use_handler_docstrings=True # Include docstrings
702
)
703
704
@post("/users", dto=UserDTO, return_dto=UserDTO)
705
def create_user(data: User) -> User:
706
"""
707
Create a new user in the system.
708
709
This endpoint creates a new user with the provided information.
710
The user ID will be automatically generated.
711
712
Args:
713
data: User information including name, email, and age
714
715
Returns:
716
Created user with generated ID
717
718
Raises:
719
ValidationException: If user data is invalid
720
ConflictException: If user with email already exists
721
"""
722
data.id = 123
723
return data
724
725
@get("/users/{user_id:int}", return_dto=UserDTO)
726
def get_user(user_id: int) -> User:
727
"""
728
Retrieve a specific user by ID.
729
730
Args:
731
user_id: The unique identifier for the user
732
733
Returns:
734
User information if found
735
736
Raises:
737
NotFoundException: If user with given ID doesn't exist
738
"""
739
return User(id=user_id, name="Alice", email="alice@example.com", age=30)
740
```
741
742
### Multiple Documentation Interfaces
743
744
```python
745
# Enable multiple documentation interfaces
746
openapi_config = OpenAPIConfig(
747
title="Multi-Interface API",
748
version="1.0.0",
749
root_schema_site="redoc", # Default interface
750
enabled_endpoints={
751
"redoc", # http://localhost:8000/schema/redoc
752
"swagger", # http://localhost:8000/schema/swagger
753
"rapidoc", # http://localhost:8000/schema/rapidoc
754
"stoplight", # http://localhost:8000/schema/stoplight
755
"openapi.json", # http://localhost:8000/schema/openapi.json
756
"openapi.yaml" # http://localhost:8000/schema/openapi.yaml
757
},
758
path="/docs", # Change base path
759
favicon_url="https://example.com/favicon.ico"
760
)
761
762
app = Litestar(
763
route_handlers=[...],
764
openapi_config=openapi_config
765
)
766
767
# Available documentation:
768
# /docs (redirects to /docs/redoc)
769
# /docs/redoc - Redoc interface
770
# /docs/swagger - Swagger UI
771
# /docs/rapidoc - RapiDoc interface
772
# /docs/stoplight - Stoplight Elements
773
# /docs/openapi.json - JSON schema
774
# /docs/openapi.yaml - YAML schema
775
```
776
777
### Custom OpenAPI Controller
778
779
```python
780
from litestar.openapi import OpenAPIController
781
from litestar import get, Response
782
783
class CustomOpenAPIController(OpenAPIController):
784
path = "/api-docs"
785
786
@get("/custom", media_type="text/html")
787
def custom_docs(self) -> Response:
788
"""Custom documentation page."""
789
html_content = """
790
<!DOCTYPE html>
791
<html>
792
<head>
793
<title>Custom API Documentation</title>
794
</head>
795
<body>
796
<h1>My API Documentation</h1>
797
<p>Welcome to our custom API documentation.</p>
798
<ul>
799
<li><a href="/api-docs/redoc">Redoc Interface</a></li>
800
<li><a href="/api-docs/swagger">Swagger UI</a></li>
801
<li><a href="/api-docs/openapi.json">JSON Schema</a></li>
802
</ul>
803
</body>
804
</html>
805
"""
806
return Response(content=html_content, media_type="text/html")
807
808
openapi_config = OpenAPIConfig(
809
title="Custom Controller API",
810
version="1.0.0",
811
openapi_controller=CustomOpenAPIController,
812
path="/api-docs"
813
)
814
```
815
816
## Types
817
818
```python { .api }
819
# OpenAPI specification types
820
OpenAPISchema = dict[str, Any]
821
SecurityRequirement = dict[str, list[str]]
822
Reference = dict[str, str]
823
824
# Component types
825
Contact = dict[str, str]
826
License = dict[str, str]
827
ExternalDocumentation = dict[str, str]
828
Tag = dict[str, Any]
829
ServerVariable = dict[str, Any]
830
831
# Schema types
832
Parameter = dict[str, Any]
833
RequestBody = dict[str, Any]
834
Response = dict[str, Any]
835
Header = dict[str, Any]
836
Example = dict[str, Any]
837
Link = dict[str, Any]
838
Callback = dict[str, Any]
839
SecurityScheme = dict[str, Any]
840
Encoding = dict[str, Any]
841
842
# Plugin types
843
OpenAPIPlugin = Any
844
OpenAPISchemaPluginProtocol = Protocol
845
846
# Operation ID creator type
847
OperationIDCreator = Callable[[str, str, list[str]], str]
848
849
# Field definition type
850
FieldDefinition = Any
851
```