or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-resources.mddocumentation.mderror-handling.mdfields.mdindex.mdinput-validation.mdmodels-marshalling.mdrequest-parsing.md

documentation.mddocs/

0

# Documentation

1

2

Automatic API documentation generation with Swagger/OpenAPI support, including interactive documentation interface and specification export. Flask-RESTPlus provides comprehensive documentation features that integrate seamlessly with API development.

3

4

## Capabilities

5

6

### Swagger Class

7

8

Main class for generating and managing Swagger/OpenAPI documentation.

9

10

```python { .api }

11

class Swagger:

12

def __init__(self, api):

13

"""

14

Initialize Swagger documentation generator.

15

16

Args:

17

api (Api): API instance to document

18

"""

19

20

def as_dict(self):

21

"""

22

Export the complete Swagger specification as a dictionary.

23

24

Returns:

25

dict: Complete Swagger/OpenAPI specification

26

"""

27

28

def extract_tags(self, api):

29

"""

30

Extract tags from API namespaces and resources.

31

32

Args:

33

api (Api): API instance

34

35

Returns:

36

list: List of tag definitions

37

"""

38

39

def extract_resource_doc(self, resource, url, route_doc=None):

40

"""

41

Extract documentation from a resource class.

42

43

Args:

44

resource (Resource): Resource class

45

url (str): Resource URL pattern

46

route_doc (dict, optional): Additional route documentation

47

48

Returns:

49

dict: Resource documentation

50

"""

51

52

def serialize_resource(self, ns, resource, url, route_doc=None, **kwargs):

53

"""

54

Serialize a resource for Swagger documentation.

55

56

Args:

57

ns (Namespace): Resource namespace

58

resource (Resource): Resource class

59

url (str): Resource URL pattern

60

route_doc (dict, optional): Route documentation

61

**kwargs: Additional serialization options

62

63

Returns:

64

dict: Serialized resource documentation

65

"""

66

67

def serialize_operation(self, doc, method):

68

"""

69

Serialize an operation (HTTP method) for Swagger.

70

71

Args:

72

doc (dict): Operation documentation

73

method (str): HTTP method name

74

75

Returns:

76

dict: Serialized operation documentation

77

"""

78

79

def serialize_definitions(self):

80

"""

81

Serialize all model definitions for Swagger.

82

83

Returns:

84

dict: Model definitions dictionary

85

"""

86

87

def serialize_schema(self, model):

88

"""

89

Serialize a model schema for Swagger.

90

91

Args:

92

model (Model): Model to serialize

93

94

Returns:

95

dict: Serialized model schema

96

"""

97

98

def register_model(self, model):

99

"""

100

Register a model for documentation.

101

102

Args:

103

model (Model): Model to register

104

105

Returns:

106

dict: Model reference

107

"""

108

109

def register_field(self, field):

110

"""

111

Register a field for documentation.

112

113

Args:

114

field (Field): Field to register

115

116

Returns:

117

dict: Field documentation

118

"""

119

```

120

121

### Documentation Functions

122

123

Utility functions for Swagger documentation generation and management.

124

125

```python { .api }

126

def ref(model):

127

"""

128

Create a JSON schema reference for a model.

129

130

Args:

131

model (Model): Model to reference

132

133

Returns:

134

dict: JSON schema reference

135

"""

136

137

def extract_path(path):

138

"""

139

Transform Flask URL rules to Swagger path format.

140

141

Args:

142

path (str): Flask URL rule (e.g., '/users/<int:user_id>')

143

144

Returns:

145

str: Swagger path format (e.g., '/users/{user_id}')

146

"""

147

148

def extract_path_params(path):

149

"""

150

Extract path parameters from a URL pattern.

151

152

Args:

153

path (str): URL pattern

154

155

Returns:

156

list: List of path parameter definitions

157

"""

158

159

def parse_docstring(obj):

160

"""

161

Parse docstrings for API documentation.

162

163

Args:

164

obj: Object with docstring (function, class, etc.)

165

166

Returns:

167

dict: Parsed docstring with summary and description

168

"""

169

170

def is_hidden(resource, route_doc=None):

171

"""

172

Check if a resource should be hidden from documentation.

173

174

Args:

175

resource: Resource class or instance

176

route_doc (dict, optional): Route documentation

177

178

Returns:

179

bool: True if resource should be hidden

180

"""

181

```

182

183

### API Documentation Blueprint

184

185

Flask blueprint for serving API documentation interface.

186

187

```python { .api }

188

class Apidoc:

189

def __init__(self):

190

"""

191

Initialize API documentation blueprint.

192

"""

193

194

def register(self, *args, **kwargs):

195

"""

196

Register the documentation blueprint with a Flask app.

197

198

Args:

199

*args: Registration arguments

200

**kwargs: Registration keyword arguments

201

"""

202

203

def swagger_static(filename):

204

"""

205

Generate URLs for Swagger static files.

206

207

Args:

208

filename (str): Static file name

209

210

Returns:

211

str: URL for static file

212

"""

213

214

def ui_for(api):

215

"""

216

Render SwaggerUI interface for an API.

217

218

Args:

219

api (Api): API instance to document

220

221

Returns:

222

str: Rendered SwaggerUI HTML

223

"""

224

225

# Pre-configured documentation blueprint instance

226

apidoc: Apidoc

227

```

228

229

### Documentation Constants

230

231

Constants used in Swagger documentation generation.

232

233

```python { .api }

234

PATH_TYPES: dict = {

235

'int': 'integer',

236

'float': 'number',

237

'string': 'string',

238

'path': 'string',

239

'uuid': 'string'

240

}

241

242

PY_TYPES: dict = {

243

int: 'integer',

244

float: 'number',

245

str: 'string',

246

bool: 'boolean',

247

list: 'array',

248

dict: 'object'

249

}

250

251

DEFAULT_RESPONSE_DESCRIPTION: str = 'Success'

252

253

DEFAULT_RESPONSE: dict = {

254

'description': DEFAULT_RESPONSE_DESCRIPTION

255

}

256

```

257

258

## Usage Examples

259

260

### Basic API Documentation

261

262

```python

263

from flask import Flask

264

from flask_restplus import Api, Resource, fields

265

266

app = Flask(__name__)

267

268

# Initialize API with documentation

269

api = Api(

270

app,

271

version='1.0',

272

title='My API',

273

description='A comprehensive API for demonstration',

274

doc='/docs/', # Documentation endpoint

275

terms_url='https://example.com/terms',

276

contact='API Support',

277

contact_email='support@example.com',

278

contact_url='https://example.com/support',

279

license='MIT',

280

license_url='https://opensource.org/licenses/MIT'

281

)

282

283

# Define models for documentation

284

user_model = api.model('User', {

285

'id': fields.Integer(required=True, description='User ID'),

286

'name': fields.String(required=True, description='Full name'),

287

'email': fields.String(required=True, description='Email address')

288

})

289

290

@api.route('/users')

291

class UserList(Resource):

292

@api.doc('list_users')

293

@api.marshal_list_with(user_model)

294

def get(self):

295

"""List all users"""

296

return [{'id': 1, 'name': 'John', 'email': 'john@example.com'}]

297

298

@api.doc('create_user')

299

@api.expect(user_model, validate=True)

300

@api.marshal_with(user_model, code=201)

301

def post(self):

302

"""Create a new user"""

303

return api.payload, 201

304

305

if __name__ == '__main__':

306

app.run(debug=True)

307

```

308

309

### Advanced Documentation Features

310

311

```python

312

from flask_restplus import Api, Namespace, Resource, fields

313

314

api = Api()

315

316

# Create namespace with detailed documentation

317

users_ns = api.namespace('users',

318

description='User management operations',

319

path='/api/users')

320

321

# Define comprehensive models

322

user_create_model = api.model('UserCreate', {

323

'name': fields.String(required=True, description='Full name', example='John Doe'),

324

'email': fields.String(required=True, description='Email address', example='john@example.com'),

325

'password': fields.String(required=True, description='Password (min 8 characters)')

326

})

327

328

user_response_model = api.model('UserResponse', {

329

'id': fields.Integer(description='Unique user ID', example=1),

330

'name': fields.String(description='Full name', example='John Doe'),

331

'email': fields.String(description='Email address', example='john@example.com'),

332

'created_at': fields.DateTime(description='Account creation timestamp'),

333

'active': fields.Boolean(description='Account status', example=True)

334

})

335

336

# Error models

337

error_model = api.model('Error', {

338

'message': fields.String(description='Error message'),

339

'code': fields.String(description='Error code')

340

})

341

342

@users_ns.route('/')

343

class UserList(Resource):

344

@api.doc('list_users',

345

description='Retrieve a paginated list of users')

346

@api.param('page', 'Page number', type='integer', default=1)

347

@api.param('per_page', 'Users per page', type='integer', default=10)

348

@api.param('search', 'Search term for filtering users', type='string')

349

@api.marshal_list_with(user_response_model)

350

@api.response(200, 'Users retrieved successfully')

351

@api.response(400, 'Invalid parameters', error_model)

352

def get(self):

353

"""

354

List users with optional filtering and pagination.

355

356

Returns a paginated list of users. Use query parameters to control

357

the results and filter by search terms.

358

"""

359

return []

360

361

@api.doc('create_user',

362

description='Create a new user account')

363

@api.expect(user_create_model, validate=True)

364

@api.marshal_with(user_response_model, code=201)

365

@api.response(201, 'User created successfully')

366

@api.response(400, 'Validation error', error_model)

367

@api.response(409, 'Email already exists', error_model)

368

def post(self):

369

"""

370

Create a new user account.

371

372

Creates a new user with the provided information. Email addresses

373

must be unique across the system.

374

"""

375

return {}, 201

376

```

377

378

### Custom Documentation Decorators

379

380

```python

381

from flask_restplus import Api, Resource, fields

382

from functools import wraps

383

384

api = Api()

385

386

def paginated_response(model, description="Paginated response"):

387

"""Custom decorator for paginated responses."""

388

pagination_model = api.model('Pagination', {

389

'page': fields.Integer(description='Current page number'),

390

'per_page': fields.Integer(description='Items per page'),

391

'total': fields.Integer(description='Total number of items'),

392

'pages': fields.Integer(description='Total number of pages')

393

})

394

395

paginated_model = api.model(f'Paginated{model.name}', {

396

'items': fields.List(fields.Nested(model), description='List of items'),

397

'pagination': fields.Nested(pagination_model, description='Pagination info')

398

})

399

400

def decorator(f):

401

@wraps(f)

402

@api.marshal_with(paginated_model)

403

@api.response(200, description)

404

def wrapper(*args, **kwargs):

405

return f(*args, **kwargs)

406

return wrapper

407

return decorator

408

409

def authenticated_required():

410

"""Custom decorator for authenticated endpoints."""

411

def decorator(f):

412

@wraps(f)

413

@api.header('Authorization', 'Bearer token', required=True)

414

@api.response(401, 'Authentication required')

415

@api.response(403, 'Insufficient permissions')

416

def wrapper(*args, **kwargs):

417

return f(*args, **kwargs)

418

return wrapper

419

return decorator

420

421

user_model = api.model('User', {

422

'id': fields.Integer,

423

'name': fields.String,

424

'email': fields.String

425

})

426

427

@api.route('/users')

428

class UserList(Resource):

429

@paginated_response(user_model, "List of users")

430

@authenticated_required()

431

def get(self):

432

"""Get paginated list of users (authenticated)"""

433

return {

434

'items': [],

435

'pagination': {'page': 1, 'per_page': 10, 'total': 0, 'pages': 0}

436

}

437

```

438

439

### Model Documentation with Examples

440

441

```python

442

from flask_restplus import Api, fields

443

from datetime import datetime

444

445

api = Api()

446

447

# Complex model with detailed documentation

448

product_model = api.model('Product', {

449

'id': fields.Integer(

450

required=True,

451

description='Unique product identifier',

452

example=12345

453

),

454

'name': fields.String(

455

required=True,

456

description='Product name',

457

example='Premium Widget',

458

min_length=1,

459

max_length=100

460

),

461

'price': fields.Fixed(

462

required=True,

463

description='Product price in USD',

464

example=29.99,

465

decimals=2,

466

min=0

467

),

468

'category': fields.String(

469

required=True,

470

description='Product category',

471

example='electronics',

472

enum=['electronics', 'clothing', 'books', 'home']

473

),

474

'in_stock': fields.Boolean(

475

description='Whether product is in stock',

476

example=True,

477

default=True

478

),

479

'tags': fields.List(

480

fields.String,

481

description='Product tags for searching',

482

example=['premium', 'featured', 'sale']

483

),

484

'specifications': fields.Raw(

485

description='Product specifications (flexible object)',

486

example={

487

'weight': '2.5 lbs',

488

'dimensions': '10x8x2 inches',

489

'warranty': '2 years'

490

}

491

),

492

'created_at': fields.DateTime(

493

description='Product creation timestamp',

494

example='2023-01-15T10:30:00Z'

495

)

496

})

497

498

# Model inheritance for documentation

499

base_entity_model = api.model('BaseEntity', {

500

'id': fields.Integer(required=True, description='Unique identifier'),

501

'created_at': fields.DateTime(description='Creation timestamp'),

502

'updated_at': fields.DateTime(description='Last update timestamp')

503

})

504

505

user_model = api.inherit('User', base_entity_model, {

506

'username': fields.String(required=True, description='Username'),

507

'email': fields.String(required=True, description='Email address'),

508

'profile': fields.Nested('UserProfile', description='User profile information')

509

})

510

511

profile_model = api.model('UserProfile', {

512

'first_name': fields.String(description='First name'),

513

'last_name': fields.String(description='Last name'),

514

'bio': fields.String(description='User biography'),

515

'avatar_url': fields.Url(description='Profile picture URL')

516

})

517

```

518

519

### Response Documentation

520

521

```python

522

from flask_restplus import Api, Resource, fields

523

524

api = Api()

525

526

# Define various response models

527

success_model = api.model('Success', {

528

'message': fields.String(description='Success message'),

529

'data': fields.Raw(description='Response data')

530

})

531

532

error_model = api.model('Error', {

533

'message': fields.String(description='Error message'),

534

'code': fields.String(description='Error code'),

535

'details': fields.Raw(description='Additional error details')

536

})

537

538

validation_error_model = api.model('ValidationError', {

539

'message': fields.String(description='Validation error message'),

540

'errors': fields.Raw(description='Field-specific validation errors')

541

})

542

543

@api.route('/products/<int:product_id>')

544

class Product(Resource):

545

@api.doc('get_product')

546

@api.response(200, 'Product found', product_model)

547

@api.response(404, 'Product not found', error_model)

548

@api.response(500, 'Internal server error', error_model)

549

def get(self, product_id):

550

"""Get a product by ID"""

551

return {}

552

553

@api.doc('update_product')

554

@api.expect(product_model, validate=True)

555

@api.response(200, 'Product updated', product_model)

556

@api.response(400, 'Validation error', validation_error_model)

557

@api.response(404, 'Product not found', error_model)

558

@api.response(409, 'Product name already exists', error_model)

559

def put(self, product_id):

560

"""Update a product"""

561

return {}

562

563

@api.doc('delete_product')

564

@api.response(204, 'Product deleted')

565

@api.response(404, 'Product not found', error_model)

566

@api.response(409, 'Cannot delete product with active orders', error_model)

567

def delete(self, product_id):

568

"""Delete a product"""

569

return '', 204

570

```

571

572

### Security Documentation

573

574

```python

575

from flask_restplus import Api, Namespace, Resource

576

577

# Define security schemes

578

authorizations = {

579

'bearer': {

580

'type': 'apiKey',

581

'in': 'header',

582

'name': 'Authorization',

583

'description': 'Bearer token authentication'

584

},

585

'api_key': {

586

'type': 'apiKey',

587

'in': 'header',

588

'name': 'X-API-Key',

589

'description': 'API key authentication'

590

},

591

'oauth2': {

592

'type': 'oauth2',

593

'flow': 'authorizationCode',

594

'authorizationUrl': 'https://example.com/oauth/authorize',

595

'tokenUrl': 'https://example.com/oauth/token',

596

'scopes': {

597

'read': 'Read access',

598

'write': 'Write access',

599

'admin': 'Admin access'

600

}

601

}

602

}

603

604

api = Api(

605

authorizations=authorizations,

606

security='bearer' # Default security requirement

607

)

608

609

# Namespace with specific security requirements

610

admin_ns = api.namespace('admin',

611

description='Admin operations',

612

security=['bearer', 'oauth2'])

613

614

@admin_ns.route('/users')

615

class AdminUserList(Resource):

616

@api.doc('admin_list_users', security='oauth2')

617

@api.response(200, 'Success')

618

@api.response(401, 'Authentication required')

619

@api.response(403, 'Admin access required')

620

def get(self):

621

"""List all users (admin only)"""

622

return []

623

624

# Public endpoint (no security)

625

@api.route('/health')

626

class Health(Resource):

627

@api.doc('health_check', security=[]) # Override default security

628

def get(self):

629

"""Health check endpoint (public)"""

630

return {'status': 'healthy'}

631

```

632

633

### Export Swagger Specification

634

635

```python

636

from flask_restplus import Api

637

import json

638

639

api = Api()

640

641

# Export complete Swagger specification

642

swagger_spec = api.__schema__

643

print(json.dumps(swagger_spec, indent=2))

644

645

# Access specific parts of the specification

646

print("API Version:", swagger_spec.get('info', {}).get('version'))

647

print("Available paths:", list(swagger_spec.get('paths', {}).keys()))

648

print("Defined models:", list(swagger_spec.get('definitions', {}).keys()))

649

650

# Save specification to file

651

with open('api_spec.json', 'w') as f:

652

json.dump(swagger_spec, f, indent=2)

653

654

# Generate OpenAPI 3.0 compatible spec (if supported)

655

try:

656

openapi_spec = api.as_dict() # May include OpenAPI 3.0 features

657

with open('openapi_spec.json', 'w') as f:

658

json.dump(openapi_spec, f, indent=2)

659

except Exception as e:

660

print(f"OpenAPI 3.0 export not supported: {e}")

661

```

662

663

### Custom Documentation Templates

664

665

```python

666

from flask_restplus import Api

667

from flask import render_template_string

668

669

api = Api()

670

671

# Custom SwaggerUI template

672

custom_ui_template = """

673

<!DOCTYPE html>

674

<html>

675

<head>

676

<title>{{ title }} - API Documentation</title>

677

<link rel="stylesheet" type="text/css" href="{{ url_for('.static', filename='swagger-ui-bundle.css') }}">

678

<style>

679

.swagger-ui .topbar { background-color: #1f4e79; }

680

.swagger-ui .topbar .download-url-wrapper { display: none; }

681

</style>

682

</head>

683

<body>

684

<div id="swagger-ui"></div>

685

<script src="{{ url_for('.static', filename='swagger-ui-bundle.js') }}"></script>

686

<script>

687

const ui = SwaggerUIBundle({

688

url: '{{ specs_url }}',

689

dom_id: '#swagger-ui',

690

presets: [

691

SwaggerUIBundle.presets.apis,

692

SwaggerUIBundle.presets.standalone

693

],

694

plugins: [

695

SwaggerUIBundle.plugins.DownloadUrl

696

],

697

deepLinking: true,

698

displayRequestDuration: true,

699

docExpansion: 'none',

700

filter: true,

701

showExtensions: true,

702

showCommonExtensions: true

703

});

704

</script>

705

</body>

706

</html>

707

"""

708

709

@api.documentation

710

def custom_ui():

711

"""Custom documentation UI"""

712

return render_template_string(

713

custom_ui_template,

714

title=api.title,

715

specs_url=api.specs_url

716

)

717

```