flask-rest-api: build a REST API on Flask using Marshmallow¶
Release v0.17.0. (Changelog)
flask-rest-api is a framework library for creating REST APIs.
It uses Flask as a webserver, and marshmallow to serialize and deserialize data. It relies extensively on the marshmallow ecosystem, using webargs to get arguments from requests, and apispec to generate an OpenAPI specification file as automatically as possible.
Guide¶
Quickstart¶
Introduction¶
flask-rest-api
makes a few assumptions about how the code should be structured.
The application should be split in Blueprint
.
It is possible to use basic Flask view functions but it is generally a good idea
to use Flask MethodView
classes instead.
Marshmallow Schema
are used to serialize parameters
and responses.
Request and response bodies are serialized as JSON.
A view function only has one successful response type and status code. All other possible responses are errors.
Simple Example¶
Here is a basic “Petstore example”, where The Pet
class is an imaginary ORM.
First instantiate an Api
with a Flask
application.
from flask import Flask
from flask.views import MethodView
import marshmallow as ma
from flask_rest_api import Api, Blueprint, abort
from .model import Pet
app = Flask('My API')
app.config['OPENAPI_VERSION'] = '3.0.2'
api = Api(app)
Define a marshmallow Schema
to expose the model.
class PetSchema(ma.Schema):
id = ma.fields.Int(dump_only=True)
name = ma.fields.String()
Define a marshmallow Schema
to validate the
query arguments.
class PetQueryArgsSchema(ma.Schema):
name = ma.fields.String()
Instantiate a Blueprint
.
blp = Blueprint(
'pets', 'pets', url_prefix='/pets',
description='Operations on pets'
)
Use MethodView
classes to organize resources,
and decorate view methods with Blueprint.arguments
and Blueprint.response
to specify request
deserialization and response serialization respectively.
Use abort
to return errors, passing kwargs used by the error
handler (handle_http_exception
) to build
the error response.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetQueryArgsSchema, location='query')
@blp.response(PetSchema(many=True))
def get(self, args):
"""List pets"""
return Pet.get(filters=args)
@blp.arguments(PetSchema)
@blp.response(PetSchema, code=201)
def post(self, new_data):
"""Add a new pet"""
item = Pet.create(**new_data)
return item
@blp.route('/<pet_id>')
class PetsById(MethodView):
@blp.response(PetSchema)
def get(self, pet_id):
"""Get pet by ID"""
try:
item = Pet.get_by_id(pet_id)
except ItemNotFoundError:
abort(404, message='Item not found.')
return item
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def put(self, update_data, pet_id):
"""Update existing pet"""
try:
item = Pet.get_by_id(pet_id)
except ItemNotFoundError:
abort(404, message='Item not found.')
item.update(update_data)
item.commit()
return item
@blp.response(code=204)
def delete(self, pet_id):
"""Delete pet"""
try:
Pet.delete(pet_id)
except ItemNotFoundError:
abort(404, message='Item not found.')
Finally, register the Blueprint
in the Api
.
api.register_blueprint(blp)
Arguments¶
To inject arguments into a view function, use the Blueprint.arguments
decorator. It allows to specify a Schema
to deserialize and validate the parameters.
When processing a request, the input data is deserialized, validated, and injected in the view function.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetQueryArgsSchema, location='query')
@blp.response(PetSchema(many=True))
def get(self, args):
return Pet.get(filters=args)
@blp.arguments(PetSchema)
@blp.response(PetSchema, code=201)
def post(self, pet_data):
return Pet.create(**pet_data)
Arguments Location¶
The following locations are allowed:
"json"
"query"
(or"querystring"
)"path"
"form"
"headers"
"cookies"
"files"
The location defaults to "json"
, which means body parameter.
Note
Blueprint.arguments
uses webargs’s
use_args
decorator internally, but
unlike use_args
, it only accepts a
single location.
Arguments Injection¶
By default, arguments are passed as a single positional dict
argument.
If as_kwargs=True
is passed, the decorator passes deserialized input data
as keyword arguments instead.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetQueryArgsSchema, location='query', as_kwargs=True)
@blp.response(PetSchema(many=True))
def get(self, **kwargs):
return Pet.get(filters=**kwargs)
This decorator can be called several times on a resource function, for instance to accept both body and query parameters. The order of the decorator calls matters as it determines the order in which the parameters are passed to the view function.
@blp.route('/')
class Pets(MethodView):
@blp.arguments(PetSchema)
@blp.arguments(QueryArgsSchema, location='query')
def post(pet_data, query_args):
return Pet.create(pet_data, **query_args)
Content Type¶
When using body arguments, a default content type is assumed depending on the
location. The location / content type mapping can be customized by modifying
Blueprint.DEFAULT_LOCATION_CONTENT_TYPE_MAPPING
.
DEFAULT_LOCATION_CONTENT_TYPE_MAPPING = {
"json": "application/json",
"form": "application/x-www-form-urlencoded",
"files": "multipart/form-data",
It is also possible to override those defaults in a single resource by passing
a string as content_type
argument to Blueprint.arguments
.
Note
The content type is only used for documentation purpose and has no impact on request parsing.
Note
Multipart requests with mixed types (file, form, etc.) are not
supported. They can be achieved but the documentation is not correctly
generated. arguments
decorator can be called multiple times on the same
view function but it should not be called with more that one request body
location. This limitation is discussed in #46.
File Upload¶
File uploads as multipart/form-data are supported for both OpenAPI 3 and OpenAPI 2.
The arguments Schema
should contain Upload
fields. The files are injected in the view function as a dict
of werkzeug
FileStorage
instances.
from werkzeug.utils import secure_filename
from flask_rest_api.fields import Upload
class MultipartFileSchema(ma.Schema):
file_1 = Upload()
@blp.route('/', methods=['POST'])
@blp.arguments(MultipartFileSchema, location='files')
@blp.response(code=201)
def func(files):
base_dir = '/path/to/storage/dir/'
file_1 = files['file_1']
file_1.save(secure_filename(file_1.filename))
Response¶
Use Blueprint.response
to specify a
Schema
class or instance to serialize the
response and a status code (defaults to 200
).
In the following examples, the GET
and PUT
methods return an instance
of Pet
serialized with PetSchema
:
@blp.route('/<pet_id>')
class PetsById(MethodView):
@blp.response(PetSchema)
def get(self, pet_id):
return Pet.get_by_id(pet_id)
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def put(self, update_data, pet_id):
pet = Pet.get_by_id(pet_id)
pet.update(update_data)
return pet
Here, the DELETE
returns an empty response so no schema is specified.
@blp.route('/<pet_id>')
class PetsById(MethodView):
@blp.response(code=204)
def delete(self, pet_id):
Pet.delete(pet_id)
If a view function returns a list of objects, the Schema
must be instanciated with many=True
.
@blp.route('/')
class Pets(MethodView):
@blp.response(PetSchema(many=True))
def get(self, args):
return Pet.get()
Note
Even if a view function returns an empty response with a default
200
code, decorating it with
Blueprint.response
is useful anyway, to return
a proper Flask Response
object.
Pagination¶
When returning a list of objects, it is generally good practice to paginate the
resource. This is where Blueprint.paginate
steps
in.
Pagination is more or less transparent to view function depending on the source of the data that is returned. Two modes are supported: pagination in view function and post-pagination.
Pagination in View Function¶
In this mode, Blueprint.paginate
injects the
pagination parameters into the view function as a
PaginationParameters
object passed
as pagination_parameters
keyword argument.
It is the responsability of the view function to return only selected elements.
The view function must also specify the total number of elements by setting it
as item_count
attribute of the PaginationParameters object.
from flask_rest_api import set_item_count
@blp.route('/')
class Pets(MethodView):
@blp.response(PetSchema(many=True))
@blp.paginate()
def get(self, pagination_parameters):
pagination_parameters.item_count = Pet.size
return Pet.get_elements(
first_item=pagination_parameters.first_item,
last_item=pagination_parameters.last_item)
Post-Pagination¶
This is the mode to use when the data is returned as a lazy database cursor. The view function does not need to know the pagination parameters. It just returns the cursor.
This mode is also used if the view function returns the complete list at no extra cost and there is no interest in specifying the pagination parameters to avoid fetching unneeded data. For instance, if the whole list is already in memory.
This mode makes the view look nicer because everything happens in the decorator and the lazy cursor.
Cursor Pager¶
In this case, Blueprint.paginate
must be passed a
pager class to take care of the pagination. flask-rest-api provides a pager
for list-like objects: Page
. For other types, a custom pager
may have to be defined.
For instance, the following custom pager works with cursor classes that support
slicing and provide a count
method returning the total number of element.
This include SQLAlchemy’s Query
,
Mongoengine’s QuerySet
,…
from flask_rest_api import Page
class CursorPage(Page):
@property
def item_count(self):
return self.collection.count()
@blp.route('/')
class Pets(MethodView):
@blp.response(PetSchema(many=True))
@blp.paginate(CursorPage)
def get(self):
return Pet.get()
Pagination Parameters¶
Once a view function is decorated with
Blueprint.paginate
, the client can request a
specific range of data by passing query arguments:
GET /pets/?page=2&page_size=10
The view function gets default values for the pagination parameters, as well as
a maximum value for page_size
.
Those default values are defined as
DEFAULT_PAGINATION_PARAMETERS = {
'page': 1, 'page_size': 10, 'max_page_size': 100}
They can be modified globally by overriding DEFAULT_PAGINATION_PARAMETERS
class attribute of the Blueprint
class or overridden in
a specific view function by passing them as keyword arguments to
Blueprint.paginate
.
Pagination Header¶
When pagination is used, a 'X-Pagination'
header is added to the response.
It contains the pagination information.
print(headers['X-Pagination'])
# {
# 'total': 1000, 'total_pages': 200,
# 'page': 2, 'first_page': 1, 'last_page': 200,
# 'previous_page': 1, 'next_page': 3,
# }
The name of the header can be changed by overriding
PAGINATION_HEADER_FIELD_NAME
class attribute of the
Blueprint
class. When setting this attribute to None
,
no pagination header is added to the response.
ETag¶
ETag is a web cache validation mechanism. It allows an API client to make conditional requests, such as
- GET a resource unless it is the same as the version in cache.
- PUT/PATCH/DELETE a resource unless the version in cache is outdated.
The first case is mostly useful to limit the bandwidth usage, the latter addresses the case where two clients update a resource at the same time (known as the “lost update problem”).
The ETag featured is available through the
Blueprint.etag
decorator. It can be disabled globally
with the ETAG_DISABLED application parameter.
flask-rest-api provides helpers to compute ETag, but ultimately, only the developer knows what data is relevant to use as ETag source, so there can be manual work involved.
ETag Computed with API Response Data¶
The simplest case is when the ETag is computed using returned data, using the
Schema
that serializes the data.
In this case, almost eveything is automatic. Only the call to
Blueprint.check_etag
is manual.
The Schema
must be provided explicitly, even
though it is the same as the response schema.
@blp.route('/')
class Pet(MethodView):
@blp.etag
@blp.response(PetSchema(many=True))
def get(self):
return Pet.get()
@blp.etag
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def post(self, new_data):
return Pet.create(**new_data)
@blp.route('/<pet_id>')
class PetById(MethodView):
@blp.etag
@blp.response(PetSchema)
def get(self, pet_id):
return Pet.get_by_id(pet_id)
@blp.etag
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def put(self, update_data, pet_id):
pet = Pet.get_by_id(pet_id)
# Check ETag is a manual action and schema must be provided
blp.check_etag(pet, PetSchema)
pet.update(update_data)
return pet
@blp.etag
@blp.response(code=204)
def delete(self, pet_id):
pet = Pet.get_by_id(pet_id)
# Check ETag is a manual action and schema must be provided
blp.check_etag(pet, PetSchema)
Pet.delete(pet_id)
ETag Computed with API Response Data Using Another Schema¶
Sometimes, it is not possible to use the data returned by the view function as ETag data because it contains extra information that is irrelevant, like HATEOAS information, for instance.
In this case, a specific ETag schema should be provided to
Blueprint.etag
. Then, it does not need to be passed to
check_etag
.
@blp.route('/')
class Pet(MethodView):
@blp.etag(PetEtagSchema(many=True))
@blp.response(PetSchema(many=True))
def get(self):
return Pet.get()
@blp.etag(PetEtagSchema)
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def post(self, new_pet):
return Pet.create(**new_data)
@blp.route('/<int:pet_id>')
class PetById(MethodView):
@blp.etag(PetEtagSchema)
@blp.response(PetSchema)
def get(self, pet_id):
return Pet.get_by_id(pet_id)
@blp.etag(PetEtagSchema)
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def put(self, new_pet, pet_id):
pet = Pet.get_by_id(pet_id)
# Check ETag is a manual action and schema must be provided
blp.check_etag(pet)
pet.update(update_data)
return pet
@blp.etag(PetEtagSchema)
@blp.response(code=204)
def delete(self, pet_id):
pet = self._get_pet(pet_id)
# Check ETag is a manual action, ETag schema is used
blp.check_etag(pet)
Pet.delete(pet_id)
ETag Computed on Arbitrary Data¶
The ETag can also be computed from arbitrary data by calling
Blueprint.set_etag
manually.
The example below illustrates this with no ETag schema, but it is also possible
to pass an ETag schema to set_etag
and
check_etag
or equivalently to
Blueprint.etag
.
@blp.route('/')
class Pet(MethodView):
@blp.etag
@blp.response(PetSchema(many=True))
def get(self):
pets = Pet.get()
# Compute ETag using arbitrary data
blp.set_etag([pet.update_time for pet in pets])
return pets
@blp.etag
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def post(self, new_data):
# Compute ETag using arbitrary data
blp.set_etag(new_data['update_time'])
return Pet.create(**new_data)
@blp.route('/<pet_id>')
class PetById(MethodView):
@blp.etag
@blp.response(PetSchema)
def get(self, pet_id):
# Compute ETag using arbitrary data
blp.set_etag(new_data['update_time'])
return Pet.get_by_id(pet_id)
@blp.etag
@blp.arguments(PetSchema)
@blp.response(PetSchema)
def put(self, update_data, pet_id):
pet = Pet.get_by_id(pet_id)
# Check ETag is a manual action
blp.check_etag(pet, ['update_time'])
pet.update(update_data)
# Compute ETag using arbitrary data
blp.set_etag(new_data['update_time'])
return pet
@blp.etag
@blp.response(code=204)
def delete(self, pet_id):
pet = Pet.get_by_id(pet_id)
# Check ETag is a manual action
blp.check_etag(pet, ['update_time'])
Pet.delete(pet_id)
ETag Not Checked Warning¶
It is up to the developer to call
Blueprint.check_etag
in the view function. It
can’t be automatic.
If ETag is enabled and check_etag
is not called,
a warning is logged at runtime. When in DEBUG or TESTING mode, an exception
is raised.
Include Headers Content in ETag¶
When ETag is computed with response data, that data may contain headers. It is up to the developer to decide whether this data should be part of the ETag.
By default, only pagination header is included in the ETag computation. This can be changed by customizing Blueprint.ETAG_INCLUDE_HEADERS.
OpenAPI¶
flask-rest-api automatically generates an OpenAPI documentation (formerly known as Swagger) for the API.
That documentation can be made accessible as a JSON file, along with a nice web interface such as ReDoc or Swagger UI.
Specify Versions¶
The version of the API and the version of the OpenAPI specification can be specified as Flask application parameters:
-
API_VERSION
Version of the API. It is copied verbatim in the documentation. It should be a string, even it the version is a number.
Default:
'1'
-
OPENAPI_VERSION
Version of the OpenAPI standard used to describe the API. It should be provided as a string.
The OpenAPI version must be passed either as application parameter or at
Api
initialization inspec_kwargs
parameters.
Add Documentation Information to Resources¶
Add Summary and Description¶
flask-rest-api uses view functions docstrings to fill the summary and description attributes of an operation object.
def get(...):
"""Find pets by ID
Return pets based on ID.
---
Internal comment not meant to be exposed.
"""
The part of the docstring following the '---'
line is ignored.
The part before the '---'
line is used as summary and description. The
first lines are used as summary. If an empty line is met, all following lines
are used as description.
The example above produces the following documentation attributes:
{
'get': {
'summary': 'Find pets by ID',
'description': 'Return pets based on ID',
}
}
The delimiter line is the line starting with the delimiter string defined in
Blueprint.DOCSTRING_INFO_DELIMITER
. This string defaults to "---"
and
can be customized in a subclass. None
means “no delimiter”: the whole
docstring is included in the docs.
Document Operations Parameters and Responses¶
Schemas passed in Blueprint.arguments
to
deserialize arguments are parsed automatically to generate corresponding
documentation. Additional example
and examples
parameters can be used
to provide examples (those are only valid for OpenAPI v3).
Likewise, schemas passed in Blueprint.response
to
serialize responses are parsed automatically to generate corresponding
documentation. Additional example
and examples
parameters can be used
to provide examples (examples
is only valid for OpenAPI v3). Additional
headers
parameters can be used to document response headers.
Document Path Parameters¶
Path parameters are automatically documented. The type in the documentation is inferred from the path parameter converter used in the URL rule. Custom path parameters should be registered for their type to be correctly determined (see below).
The Blueprint.route
method takes a parameters
argument to pass documentation for parameters that are shared by all operations
of a path. It can be used to pass extra documentation, such as examples, for
path parameters.
Pass Extra Documentation Information¶
flask-rest-api tries to document the API as automatically as possible and to provide explicit means to pass extra-information that can’t be inferred from the code, such as descriptions, examples, etc.
The Blueprint.doc
decorator provides a means to pass
extra documentation information. It comes in handy if an OpenAPI feature is not
supported, but it suffers from a few limitations, and it should be considered
a last resort solution until flask-rest-api is improved to fit the need.
Known issues and alternatives are discussed in issue #71.
Populate the Root Document Object¶
Additional root document attributes can be passed either in the code, in
Api
parameter spec_kwargs
, or as Flask app configuration
parameters.
app.config['API_SPEC_OPTIONS'] = {'x-internal-id': '2'}
api = Api(app, spec_kwargs={'host': 'example.com', 'x-internal-id': '1'})
Note that app.config
overrides spec_kwargs
. The example above produces
{'host': 'example.com', 'x-internal-id': '2', ...}
Note
Again, flask-rest-api tries to provide as much information as possible, but some values can only by provided by the user.
When using OpenAPI v2, basePath is automatically set from the value of the flask parameter APPLICATION_ROOT. In OpenAPI v3, basePath is removed, and the servers attribute can only be set by the user.
Document Top-level Components¶
Documentation components can be passed by accessing the internal apispec
Components
object.
api = Api(app)
api.spec.components.parameter(
'Pet name',
'query',
{'description': 'Item ID', 'format': 'int32', 'required': True}
)
Register Custom Fields¶
Standard marshmallow Field
classes are
documented with the correct type and format.
When using custom fields, the type and format must be passed, either explicitly
or by specifying a parent field class, using Api.register_field()
:
# Map to ('string', 'ObjectId') passing type and format
api.register_field(ObjectId, 'string', 'ObjectId')
# Map to ('string') passing type
api.register_field(CustomString, 'string', None)
# Map to ('integer, 'int32') passing a code marshmallow field
api.register_field(CustomInteger, ma.fields.Integer)
Register Custom Path Parameter Converters¶
Likewise, standard types used as path parameter converters in the flask routes are correctly documented, but custom path converters must be registered.
The Api.register_converter()
allows to register a converter in the
Api
object to generate an accurate documentation.
# Register MongoDB's ObjectId converter in Flask application
app.url_map.converters['objectid'] = ObjectIdConverter
# Register converter in Api
api.register_converter(ObjectIdConverter, 'string', 'ObjectID')
@blp.route('/pets/{objectid:pet_id}')
...
Enforce Order in OpenAPI Specification File¶
When a Blueprint
is registered, a tag is created with
the Blueprint
name. The display order in the interface is the Blueprint
registration order. And the display order inside a tag is the order in which
the resources are defined in the Blueprint
.
In the OpenAPI specification file, the fields of a Schema
are documented as
schema properties. Although objects are not ordered in JSON, OpenAPI
graphical interfaces tend to respect the order in which the properties are
defined in the properties
object in the specification file.
When using an ordererd Schema
, the fields definition order is preserved
when generating the specification file and the properties are displayed in
that order.
This is typically done in a base class:
class MyBaseSchema(ma.Schema):
class Meta:
ordered = True
class User(MyBaseSchema):
name = ma.fields.String()
surname = ma.fields.String()
Passing ordered
Meta attribute is not necessary when using a Python version
for which dictionaries are always ordered (>= 3.7 or CPython 3.6).
Serve the OpenAPI Documentation¶
Now that that the documentation is generated, it should be made available to the clients. flask-rest-api can define routes to provide both the documentation as a JSON file and a nice web interface to browse it interactively. This feature is accessible through Flask app parameters.
-
OPENAPI_URL_PREFIX
Defines the base path for both the JSON file and the UI. If
None
, the documentation is not served and the following parameters are ignored.Default:
None
-
OPENAPI_JSON_PATH
Path to the JSON file, relative to the base path.
Default:
openapi.json
Both ReDoc and Swagger UI interfaces are available to present the API.
Their configuration logics are similar. If a path is set, then flask-rest-api creates a route in the application to serve the interface page, using the JS script from a user defined URL, if any, or from a CDN URL built with the version number.
-
OPENAPI_REDOC_PATH
If not
None
, path to the ReDoc page, relative to the base path.Default:
None
-
OPENAPI_REDOC_URL
URL to the ReDoc script. If
None
, a CDN version is used.Default:
None
-
OPENAPI_REDOC_VERSION
ReDoc version as string. Should be an existing version number,
latest
(latest 1.x version) ornext
(latest 2.x version).This is used to build the CDN URL if
OPENAPI_REDOC_URL
isNone
.On a production instance, it is recommended to specify a fixed version number.
Default:
'latest'
-
OPENAPI_SWAGGER_UI_PATH
If not
None
, path to the Swagger UI page, relative to the base path.Default:
None
-
OPENAPI_SWAGGER_UI_URL
URL to the Swagger UI script. If
None
, a CDN version is used.Default:
None
-
OPENAPI_SWAGGER_UI_VERSION
Swagger UI version as string. Contrary to ReDoc, there is no default value pointing to the latest version, so it must be specified.
This is used to build the CDN URL if
OPENAPI_SWAGGER_UI_URL
isNone
.Default:
None
-
OPENAPI_SWAGGER_UI_SUPPORTED_SUBMIT_METHODS
List of methods for which the ‘Try it out!’ feature is enabled. Should be a list of lowercase HTTP methods.
Passing an empty list disables the feature globally.
Default:
['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']
Warning
The version strings are not checked by flask-rest-api. They are used as is to build the URL pointing to the UI script. Typos won’t be caught.
API Reference¶
API Reference¶
-
flask_rest_api.
abort
(http_status_code, exc=None, **kwargs)[source]¶ Raise a HTTPException for the given http_status_code. Attach any keyword arguments to the exception for later processing.
From Flask-Restful. See NOTICE file for license information.
Api¶
-
class
flask_rest_api.
Api
(app=None, *, spec_kwargs=None)[source]¶ Main class
Provides helpers to build a REST API using Flask.
Parameters: - app (Flask) – Flask application
- spec_kwargs (dict) – kwargs to pass to internal APISpec instance
The
spec_kwargs
dictionary is passed as kwargs to the internal APISpec instance. flask-rest-api adds a few parameters to the original parameters documented inapispec.APISpec
:Parameters: - flask_plugin (apispec.BasePlugin) – Flask plugin
- marshmallow_plugin (apispec.BasePlugin) – Marshmallow plugin
- extra_plugins (list|tuple) – List of additional
BasePlugin
instances - openapi_version (str) – OpenAPI version. Can also be passed as application parameter OPENAPI_VERSION.
This allows the user to override default Flask and marshmallow plugins.
title and version APISpec parameters can’t be passed here, they are set according to the app configuration.
For more flexibility, additional spec kwargs can also be passed as app parameter API_SPEC_OPTIONS.
-
register_converter
(converter, conv_type, conv_format=None)¶ Register custom path parameter converter
Parameters: - converter (BaseConverter) – Converter Subclass of werkzeug’s BaseConverter
- conv_type (str) – Parameter type
- conv_format (str) – Parameter format (optional)
Example:
# Register MongoDB's ObjectId converter in Flask application app.url_map.converters['objectid'] = ObjectIdConverter # Register converter in Api api.register_converter(ObjectIdConverter, 'string', 'ObjectID') @blp.route('/pets/{objectid:pet_id}') ... api.register_blueprint(blp)
Once the converter is registered, all paths using it will have corresponding path parameter documented with the right type and format.
Should be called before registering paths with
Blueprint.route
.
-
register_field
(field, *args)¶ Register custom Marshmallow field
Registering the Field class allows the Schema parser to set the proper type and format when documenting parameters from Schema fields.
Parameters: field (Field) – Marshmallow Field class *args
can be:- a pair of the form
(type, format)
to map to - a core marshmallow field type (then that type’s mapping is used)
Examples:
# Map to ('string', 'ObjectId') passing type and format api.register_field(ObjectId, 'string', 'ObjectId') # Map to ('string') passing type api.register_field(CustomString, 'string', None) # Map to ('integer, 'int32') passing a code marshmallow field api.register_field(CustomInteger, ma.fields.Integer)
Should be called before registering schemas with
schema
.- a pair of the form
-
handle_http_exception
(error)¶ Return a JSON response containing a description of the error
This method is registered at app init to handle
HTTPException
.- When
abort
is called in the code, anHTTPException
is triggered and Flask calls this handler. - When an exception is not caught in a view, Flask makes it an
InternalServerError
and calls this handler.
flask_rest_api republishes webargs’s
abort
. Thisabort
allows the caller to pass kwargs and stores them inexception.data
so that the error handler can use them to populate the response payload.Extra information expected by this handler:
- message (
str
): a comment - errors (
dict
): errors, typically validation errors in - parameters and request body
- errors (
- headers (
dict
): additional headers
- When
Blueprint¶
-
class
flask_rest_api.
Blueprint
(*args, **kwargs)[source]¶ Blueprint that registers info in API documentation
-
arguments
(schema, *, location='json', content_type=None, required=True, description=None, example=None, examples=None, **kwargs)¶ Decorator specifying the schema used to deserialize parameters
Parameters: - schema (type|Schema) – Marshmallow
Schema
class or instance used to deserialize and validate the argument. - location (str) – Location of the argument.
- content_type (str) – Content type of the argument.
Should only be used in conjunction with
json
,form
orfiles
location. The default value depends on the location and is set inBlueprint.DEFAULT_LOCATION_CONTENT_TYPE_MAPPING
. This is only used for documentation purpose. - required (bool) – Whether argument is required (default: True).
- description (str) – Argument description.
- example (dict) – Parameter example.
- examples (list) – List of parameter examples.
- kwargs (dict) – Keyword arguments passed to the webargs
use_args
decorator used internally.
The required and description only affect body arguments (OpenAPI 2) or requestBody (OpenAPI 3), because the docs expose the whole schema. For other locations, the schema is turned into an array of parameters and the required/description value of each parameter item is taken from the corresponding field in the schema.
The example and examples parameters are mutually exclusive and should only be used with OpenAPI 3 and when location is
json
.See Arguments.
- schema (type|Schema) – Marshmallow
-
response
(schema=None, *, code=200, description=None, example=None, examples=None, headers=None)¶ Decorator generating an endpoint response
Parameters: - schema –
Schema
class or instance. If not None, will be used to serialize response data. - code (int|str|HTTPStatus) – HTTP status code (default: 200). Used if none is returned from the view function.
- description (str) – Description of the response (default: None).
- example (dict) – Example of response message.
- examples (list) – Examples of response message.
- headers (dict) – Headers returned by the response.
The decorated function is expected to return the same types of value than a typical flask view function, except the body part may be an object or a list of objects to serialize with the schema, rather than a
string
.If the decorated function returns a
Response
object, theschema
andcode
parameters are only used to document the resource.The example and examples parameters are mutually exclusive. The latter should only be used with OpenAPI 3.
The example, examples and headers parameters are only used to document the resource.
See Response.
- schema –
-
paginate
(pager=None, *, page=None, page_size=None, max_page_size=None)¶ Decorator adding pagination to the endpoint
Parameters: - pager (Page) – Page class used to paginate response data
- page (int) – Default requested page number (default: 1)
- page_size (int) – Default requested page size (default: 10)
- max_page_size (int) – Maximum page size (default: 100)
If a
Page
class is provided, it is used to paginate the data returned by the view function, typically a lazy database cursor.Otherwise, pagination is handled in the view function.
The decorated function may return a tuple including status and/or headers, like a typical flask view function. It may not return a
Response
object.See Pagination.
-
etag
(etag_schema=None)¶ Decorator generating an endpoint response
Parameters: etag_schema – Schema
class or instance. If not None, will be used to serialize etag data.Can be used as either a decorator or a decorator factory:
Example:
@blp.etag def view_func(...): ... @blp.etag(EtagSchema) def view_func(...): ...
The
etag
decorator expects the decorated view function to return aResponse
object. It is the case if it is decorated with theresponse
decorator.See ETag.
-
check_etag
(etag_data, etag_schema=None)¶ Compare If-Match header with computed ETag
Raise 412 if If-Match-Header does not match.
Must be called from resource code to check ETag.
Unfortunately, there is no way to call it automatically. It is the developer’s responsability to do it. However, a warning is logged at runtime if this function was not called.
-
set_etag
(etag_data, etag_schema=None)¶ Set ETag for this response
Raise 304 if ETag identical to If-None-Match header
Must be called from resource code, unless the view function is decorated with the
response
decorator, in which case the ETag is computed by default from response data ifset_etag
is not called.Logs a warning if called in a method other than one of GET, HEAD, POST, PUT, PATCH.
-
static
doc
(**kwargs)[source]¶ Decorator adding description attributes to a view function
Values passed as kwargs are copied verbatim in the docs
Example:
@blp.doc(description="Return pets based on ID", summary="Find pets by ID" ) def get(...): ...
-
register_views_in_doc
(app, spec)[source]¶ Register views information in documentation
If a schema in a parameter or a response appears in the spec schemas section, it is replaced by a reference in the parameter or response documentation:
“schema”:{“$ref”: “#/components/schemas/MySchema”}
-
route
(rule, *, parameters=None, **options)[source]¶ Decorator to register url rule in application
Also stores doc info for later registration
Use this to decorate a
MethodView
or a resource function.Parameters: - rule (str) – URL rule as string.
- endpoint (str) – Endpoint for the registered URL rule (defaults to function name).
- parameters (list) – List of parameters relevant to all operations in this path, only used to document the resource.
- options (dict) – Options to be forwarded to the underlying
werkzeug.routing.Rule
object.
-
Project Info¶
Changelog¶
0.17.0 (2019-09-19)¶
Features:
- Backwards-incompatible: Only return status code and short name in error handler (#84).
- Backwards-incompatible: Remove logging from error handler. Logging can be
achieved in application code by overriding
handle_http_exception
. Remove_prepare_error_response_content
. Reponse payload is computed inhandle_http_exception
. (#85) - Backwards-incompatible: Remove
InvalidLocationError
. The mapping from webargs locations to OAS locations is done in apispec and no exception is raised if an invalid location is passed. (#81) - Add
content_type
argument toBlueprint.arguments
and provide reasonable default content type forform
andfiles
(#83). - Add
description
parameter toBlueprint.arguments
to pass description forrequestBody
(#93). - Allow customization of docstring delimiter string (#49).
- Support file uploads as multipart/form-data (#97).
Bug fixes:
- Fix documentation of
form
andfiles
arguments: userequestBody
in OAS3, document content type (#83).
Other changes:
- Backwards-incompatible: Don’t republish
NestedQueryArgsParser
anymore. This belongs to user code and can be copied from webargs doc (#94). - Backwards-incompatible: Bump minimum apispec version to 3.0.0.
0.16.1 (2019-07-15)¶
Bug fixes:
- Fix detection of unhandled exceptions in error handler for Flask=>1.1.0 (#82).
Other changes:
- Bump minimum Flask version to 1.1.0. From this version on, uncaught
exceptions are passed to the error handler as
InternalServerError
with the exception attached asoriginal_exception
attribute. (#82)
0.16.0 (2019-06-20)¶
Features:
- Add
parameters
argument toBlueprint.route
to pass documentation for parameters that are shared by all operations of a path (#78).
Other changes:
- Backwards-incompatible: Bump minimum apispec version to 2.0.0.
- Backwards-incompatible: Path parameters documentation passed in
Blueprint.doc
is no longer merged with automatic documentation. It should be passed inBlueprint.route
instead. - Backwards-incompatible: Remove
Api.schema
andApi.definition
. Those methods are useless sinceSchema
components are automatically registered by apispec. Manual component registration is still possible using the internal apispecComponents
object. (#75)
0.15.0 (2019-05-09)¶
Features:
- Add parameters to pass examples and headers in
Blueprint.response
decorator (#63). - Add parameters to pass examples for
requestBody
in OpenAPI v3 inBlueprint.arguments
decorator (#68). - Support status codes expressed as
HTTPStatus
inBlueprint.response
decorator (#60). Thanks @Regzand for reporting.
Other changes:
- Bump minimum apispec version to 1.3.2.
- Bump minimum werkzeug version to 0.15. With 0.14.x versions, 412 responses are returned with no content.
- Backwards-incompatible: When using
Blueprint.doc
decorator to provide additional documentation to the response described in theBlueprint.response
decorator, the user must use the same format (str
,int
orHTTPStatus
) to express the status code in both decorators. This is a side-effect of (#60). Now that headers and examples can be described inBlueprint.response
, this should not be a common use case.
0.14.1 (2019-04-18)¶
Features:
- Official Python 3.7 support (#45).
- Rename
Api.definition
asApi.schema
. KeepApi.definition
as an alias toApi.schema
for backward compatibility (#53).
Bug fixes:
- Fix passing route with path parameter default value (#58). Thanks @zedrdave for reporting.
- When no descrition is provided to
Blueprint.response
, don’t add an empty string as description in the docs. - Fix returning a
tuple
subclass from a view function. Only rawtuple
instances are considered as Flask’s (return value, status, headers).tuple
subclasses are treated aslist
and can be paginated/dumped. Rawtuple
return values should be cast to another type (e.g.list
) to be distinguished from (return value, status, headers) tuple. (#52) Thanks @asyncee for reporting.
0.14.0 (2019-03-08)¶
Features:
- Allow view functions decorated with
response
to return aResponse
object or a tuple with status and/or headers (#40). - Allow view functions decorated with
paginate
to return a tuple with status and/or headers (#40). The pagination header is now passed in the response tuple. Users relying on undocumentedget_context()['headers']
as a workaround to pass headers must update their code to pass headers in the response tuple as well.
Bug fixes:
- Fix ETag computation when headers contain a duplicate key.
0.13.1 (2019-02-13)¶
Features:
- Register Werkzeug’s
UUIDConverter
inApi
so thatuuid
path parameters are correctly documented.
0.13.0 (2019-02-12)¶
Features:
- Add
flask_plugin
andmarshmallow_plugin
spec kwargs to allow overriding base plugins. - Backwards-incompatible: Rename
plugins
spec kwarg intoextra_plugins
. - Backwards-incompatible: Don’t default to OpenAPI version 2.0. The version
must now be specified, either as
OPENAPI_VERSION
app parameter or asopenapi_version
spec kwarg. - Support apispec 1.0.0.
- Backwards-incompatible: Drop support for apispec 0.x.
0.12.0 (2018-12-02)¶
Features:
- Backwards-incompatible:
Api.register_converter
doesn’t register converter in Flask app anymore. It should be registered manually usingapp.url_map.converters['converter_name'] = Converter
. Api.definition
,Api.register_field
andApi.register_converter
can be called before app initialization. The information is buffered and passed to the internalAPISpec
object when it is created, inApi.init_app
.
0.11.1 (2018-11-20)¶
Features:
- The
HTTP_METHODS
list that defines the order of the methods in the spec is now a class attribute ofBlueprint
. It can be overridden to enforce another order.
Bug fixes:
- Import
Mapping
fromcollections.abc
rather thancollections
. The latter is deprecated in Python 3.7 and will be removed in 3.8. - Merge manual doc added with
Blueprint.doc
with automatic documentation after auto doc is prepared (i.e. adapted to OpenAPI version) (#19). Thanks @fbergroth for reporting. - Merge automatic path parameter documentation with existing manual doc rather than append as duplicate parameter (#23). Thanks @congenica-andrew for reporting.
- Fix path parameter documentation structure when using OpenAPI v3.
- Document http status codes as strings, not integers.
- Fix use of Swagger UI config parameter
OPENAPI_SWAGGER_UI_URL
.
Other changes:
- 100% test coverage !
0.11.0 (2018-11-09)¶
Features:
- Backwards-incompatible: Rework of the ETag feature. It is now accesible
using dedicated
Blueprint.etag
decorator.check_etag
andset_etag
are methods ofBlueprint
andetag.INCLUDE_HEADERS
is replaced withBlueprint.ETAG_INCLUDE_HEADERS
. It is enabled by default (only on views decorated withBlueprint.etag
) and disabled withETAG_DISABLED
application configuration parameter.is_etag_enabled
is now private. (#21) - Backwards-incompatible: The
response
decorator returns aResponse
object rather than a (Response
object, status code) tuple. The status code is set in theResponse
object. - Support apispec 1.0.0b5.
0.10.0 (2018-10-24)¶
Features:
- Backwards-incompatible: Don’t prefix all routes in the spec with
APPLICATION_ROOT
. If using OpenAPI v2, setAPPLICATION_ROOT
asbasePath
. If using OpenAPI v3, the user should specifyservers
manually. - Backwards-incompatible: In testing and debug modes,
verify_check_etag
not only logs a warning but also raisesCheckEtagNotCalledError
ifcheck_etag
is not called in a resource that needs it.
0.9.2 (2018-10-16)¶
Features:
Api.register_blueprint
passes**options
keyword parameters toapp.register_blueprint
to overrideBlueprint
defaults. Thanks @dryobates for the suggestion.
0.9.1 (2018-10-11)¶
Features:
- Support apispec 1.0.0b3.
Bug fixes:
- Fix crash when serving documentation at root of application. Thanks @fbergroth for the suggestion.
0.9.0 (2018-10-01)¶
Features:
- Backwards-incompatible: When pagination parameters are out of range, the API does not return a 404 error anymore. It returns a 200 code with an empty list and pagination metadata (#10).
- Backwards-incompatible: Remove dependency on python-dateutil. This is an optional marshmallow dependency. Whether it is needed to deserialize date, time, or datetime strings depends on the application.
- Rework internal features by using mixin classes. This makes the code cleaner and adds customization possibilities (#9).
- Backwards-incompatible:
DEFAULT_PAGINATION_PARAMETERS
is a class attribute ofBlueprint
. - Backwards-incompatible: When no
Page
class is passed topagination
, (i.e. when doing pagination in view function), the pagination parameters are passed as aPaginationParameters
object. The item count must be passed by setting it asitem_count
attribute of thePaginationParameters
object. Theset_item_count
function is removed. - The pagination header name can be configured by overriding
PAGINATION_HEADER_FIELD_NAME
class attribute ofBlueprint
. If set toNone
, no pagination header is added to the response. - Backwards-incompatible: The
paginate
decorator doesn’t useNestedQueryFlaskParser
by default. It is renamed asNestedQueryArgsParser
and it can be used by overridingBlueprint.ARGUMENTS_PARSER
. - Backwards-incompatible: Drop Flask 0.x support. Flask>=1.0 is now required.
- Default error handler is registered for generic
HTTPException
. Other extensions may register other handlers for specific exceptions or codes (#12).
0.8.1 (2018-09-24)¶
Features:
- Add page (page number) to pagination metadata.
- Set produces and consumes root document attributes when using OpenAPI v2.
Bug fixes:
- Document body parameter correctly when using OpenAPI v3.
0.8.0 (2018-09-20)¶
Features:
- Add
API_SPEC_OPTIONS
app config parameter. Thanks @xalioth for the suggestion. - Backwards-incompatible:
Api
accepts aspec_kargs
parameter, passed as kwargs to the internalAPISpec
instance.spec_plugins
is removed, plugins shall be passed asspec_kwargs={'plugins': [...]}
. - Backwards-incompatible: Get summary and description from docstrings (#5).
- Add support for marshmallow 3.0.0b13. 2.x and 3b are now supported.
- Add support for apispec 1.0.0b2. 0.x and 1b are now supported.
Bug fixes:
0.7.0 (2018-07-19)¶
Other changes:
- Backwards-incompatible: Remove
_wrapper_class
fromPage
. Creating a custom pager is easier by just overridingPage
methods. - Backwards-incompatible: Let
OPENAPI_SWAGGER_UI_SUPPORTED_SUBMIT_METHODS
default to “all methods” list.
0.6.1 (2018-06-29)¶
Bug fixes:
- Swagger UI integration: respect
OPENAPI_SWAGGER_UI_URL
configuration paramater. Api.register_field
: useAPISpec.register_field
rather than accessself.spec.ma_plugin
directly.
0.6.0 (2018-06-29)¶
Features:
- Backwards-incompatible: Use apispec 0.39.0 plugin class interface.
- Backwards-incompatible: Expose APISpec’s
register_field
andregister_converter methods
fromApi
object.Api.register_converter
signature is modified to makename
parameter optional. - Pass extra apispec plugins to internal APISpec instance.
- Backwards-incompatible: Drop official support for Python 3.4.
0.5.2 (2018-06-21)¶
Features:
- Pass OpenAPI version as
OPENAPI_VERSION
app config parameter. - Add Swagger UI (3.x) integration.
0.5.0 (2018-06-05)¶
Features:
- Backwards-incompatible: In
Blueprint.route
, the endpoint name defaults to the function name with the case unchanged. Before this change, the name was lowercased. - Backwards-incompatible: Pagination is now managed by dedicated
Blueprint.paginate
decorator. - Add
etag.INCLUDE_HEADERS
to specify which headers to use for ETag computation (defaults to['X-Pagination']
). - In
verify_check_etag
, endpoint name is added to the warning message.
0.4.2 (2018-04-27)¶
Bug fixes:
- Pagination: don’t crash if
item_count
is not set, just log a warning and set no pagination header. - API spec: Fix leading/trailing slash issues in api-docs Blueprint. Fixes compatibility with Flask 1.0.
0.4.1 (2018-04-17)¶
Features:
- Allow multiple calls to
Blueprint.arguments
on a view function. - Enforce order of fields in
PaginationParametersSchema
andPaginationMetadataSchema
. - Minor improvements in test_examples.py.
0.4.0 (2018-04-05)¶
Features:
- Backwards-incompatible: The case of a parameter both in URL and in arguments Schema is now unsupported.
- Backwards-incompatible: By default, Schema parameter passed in
Blueprint.arguments
is documented as required. - Backwards-incompatible:
APISpec.register_field
now uses apispec API. It must be passed a(type, format)
couple or an already registeredField
class (this includes base marshmallowFields
. When using(type, format)
,format
doesn’t default toNone
anymore. - Preserve order when serving the spec file: - Fields are printed in declaration order if Schema.Meta.ordered is True - Methods in a method view are printed in this order: [‘OPTIONS’, ‘HEAD’, ‘GET’, ‘POST’, ‘PUT’, ‘PATCH’, ‘DELETE’] - Paths are added in declaration order
Bug fixes:
- Document response as array when using paginate_with.
0.3.0 (2018-03-02)¶
Features:
- Add leading and trailing
/
to OPENAPI_URL_PREFIX if missing. - Backwards-incompatible: Change default URL path for OpenAPI JSON to
'openapi.json'
.
Bug fixes:
- Fix OpenAPI docs URL paths.
- Backwards-incompatible:
Blueprint.route(self, rule, **options)
matchesflask
’sBlueprint
signature.
0.2.0 (2018-03-02)¶
Features:
format
parameter inregister_converter
andregister_field
is now optional and defaults toNone
.- APISpec inherits from original apispec.APISpec.
- Backwards-incompatible: The internal
APISpec
instance is now exposed as public attributespec
ofApi
.register_converter
andregister_field
are not proxied anymore byApi
and must be called onspec
. - Backwards-incompatible:
Api.register_converter
takes aname
parameter and registers a converter in theFlask
application as well as in its internalAPISpec
instance. - Backwards-incompatible:
Api.register_spec_plugin
is removed.api.register_spec_plugin(...)
shall be replaced withapi.spec.setup_plugin(...)
.
0.1.0 (2018-02-16)¶
First release.
License¶
MIT License
Copyright (c) 2016-2019 Nobatek/INEF4 and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Authors¶
Leads¶
- Jérôme Lafréchoux @lafrech
- David Fédérique @davidfrederique
Contributors (chronological)¶
- Ryan Yin @ryan4yin
- Douglas Thor @dougthor42
- Steven Loria @sloria