or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-routing.mdconfiguration.mddto.mdexceptions.mdhttp-handlers.mdindex.mdmiddleware.mdopenapi.mdplugins.mdrequest-response.mdsecurity.mdtesting.mdwebsocket.md

openapi.mddocs/

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

```