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
```