Flask-APISpec
Flask-APISpec provides a convenient layer for integrating APISpec and webargs/marshmallow with Flask applications to automatically generate OpenAPI/Swagger documentation for REST APIs. It simplifies schema definition and request/response marshaling. The current version is 0.11.4, and releases are infrequent, often following `apispec` updates or Flask compatibility requirements.
Common errors
-
ModuleNotFoundError: No module named 'flask_apispec.extension'
cause Flask-APISpec is not installed or installed incorrectly, likely missing the `[marshmallow]` or `[webargs]` extras.fixEnsure `flask-apispec` is installed with its necessary dependencies, e.g., `pip install flask-apispec[marshmallow]`. -
TypeError: can only concatenate str (not NoneType) to str
cause A `doc` decorator argument (like `description`) or a schema field expects a string but received `None`, which Flask or `apispec` cannot process.fixReview your `@doc` decorator arguments and Marshmallow schema fields to ensure all string-expected values are actual strings and not `None`. -
AttributeError: 'APISpec' object has no attribute 'register_converter'
cause This error typically occurs when `flask-apispec` is used with `apispec >= 5.0`, which removed the `register_converter` method from `APISpec`.fixThis method is now a no-op within `flask-apispec` when `apispec >= 5.0` is detected. If you were using it for custom schema types, you might need to integrate a custom `Plugin` with `apispec` directly, or ensure `apispec.ext.marshmallow.MarshmallowPlugin` is used correctly if registering Marshmallow fields. -
Validation Error: 'schema' is a required property
cause When defining parameters for the `@doc` decorator, especially for `requestBody`, `flask-apispec` and `apispec` expect a schema reference (e.g., `schema=YourSchema`) rather than a simple dictionary or missing schema definition.fixFor complex parameters, define a Marshmallow `Schema` and pass it to the `schema` key in the `@doc` decorator's `params` or `requestBody` definition. Example: `@doc(requestBody={'content': {'application/json': {'schema': ItemSchema}}})`.
Warnings
- breaking Major version changes in `apispec` (e.g., v3 to v4, v4 to v5) introduce breaking changes, which `flask-apispec` eventually incorporates. Always check `apispec` release notes when upgrading, as `flask-apispec`'s `0.11.x` series is compatible with `apispec` 5.x.
- gotcha The `openapi_version` in `APISPEC_SPEC` configuration (e.g., '2.0.0', '3.0.0', '3.1.0') significantly impacts the generated spec and supported features. `apispec` 5.x defaults to '3.0.0' or '3.1.0' but older examples might use '2.0.0'.
- gotcha The `doc` decorator's `params` argument structure for complex types or nested schemas can be tricky and requires careful mapping to OpenAPI specifications, often involving a `schema` key with a Marshmallow `Schema` instance.
- gotcha `use_kwargs` and `marshal_with` decorators require a `location` argument (e.g., `'json'`, `'query'`, `'headers'`, `'form'`) or a default configured via `APISPEC_DEFAULT_LOCATION` in `app.config`. Omitting it can lead to unexpected behavior or ignored parameters.
Install
-
pip install flask-apispec[marshmallow] -
pip install flask-apispec[webargs]
Imports
- FlaskApiSpec
from flask_apispec.extension import FlaskApiSpec
- doc
from flask_apispec import doc
- use_kwargs
from flask_apispec import use_kwargs
- marshal_with
from flask_apispec import marshal_with
- MethodResource
from flask_apispec.views import MethodResource
Quickstart
from flask import Flask, jsonify
from flask_apispec import doc, use_kwargs, marshal_with
from flask_apispec.extension import FlaskApiSpec
from marshmallow import Schema, fields
app = Flask(__name__)
app.config.update({
'APISPEC_SPEC': {
'title': 'My Awesome API',
'version': 'v1',
'openapi_version': '3.0.0' # Recommended for modern APIs
},
'APISPEC_SWAGGER_URL': '/swagger/',
'APISPEC_SWAGGER_UI_URL': '/swagger-ui/'
})
docs = FlaskApiSpec(app)
class ItemSchema(Schema):
id = fields.Int(dump_only=True)
name = fields.Str(required=True, description='Name of the item')
description = fields.Str(required=False, description='Description of the item')
items_db = {}
next_id = 1
@app.route('/items', methods=['POST'])
@doc(description='Create a new item', tags=['Items'])
@use_kwargs(ItemSchema, location='json')
@marshal_with(ItemSchema, code=201)
def create_item(**kwargs):
global next_id
item = kwargs
item['id'] = next_id
items_db[next_id] = item
next_id += 1
return jsonify(item), 201
@app.route('/items/<int:item_id>', methods=['GET'])
@doc(description='Get an item by ID', tags=['Items'], params={'item_id': {'description': 'Item ID', 'type': 'integer'}})
@marshal_with(ItemSchema, code=200)
def get_item(item_id):
item = items_db.get(item_id)
if item:
return jsonify(item), 200
return jsonify({'message': 'Item not found'}), 404
docs.register(create_item)
docs.register(get_item)
if __name__ == '__main__':
app.run(debug=True)