Content-negotiation¶
Content-negotiation is, in case of Flask-arrest, accepting only content-types that a server can process and serving the client only representations of data that it can understand.
A simple example¶
from flask_arrest import RestBlueprint, serialize_response
api = RestBlueprint('api', __name__)
# for outgoing data, the app additionally supports CSV in addition to
# application/json
api.outgoing.add_mimetype('text/csv')
@api.content_renderer.renders('text/csv')
def render_csv(data):
"""Given any temperature data, this function returns a CSV-string of it"""
# ...
@api.route('/temperatures/', methods=['POST'])
def upload_data():
"""Processes uploaded temperatures and adds the to the database."""
# ...
@api.route('/temperatures/', methods=['GET'])
def query_temperatures():
"""Allows querying tepmperature records."""
# we use static fixtures in this example
temps = [
{'measured': DateTime(2014, 02, 04, 17, 38),
'temperature': 6},
{'measured': DateTime(2014, 02, 04, 19, 12),
'temperature': 4}
]
# render the data for a specific content-type. if no content-type is
# given, the best (according to client-preference) type registered
# (see api.outgoing) will be delivered
return serialize_response(temps)
The (incomplete) application above supports one incoming mimetype [1] and two
outgoing ones (application/json
is the overridable default in both cases,
see incoming
and
outgoing
). This allows the
client to specify his preferred format for receiving data using HTTP headers.
[1] | In a real application, it would be a good idea to use a vendor-specific mimetype, such as
application/vnd.temperatureapp+json . |
Content-negotiation is handled automatically by any
Blueprint
that has the
ContentNegotiationMixin
mixed in.
Incoming content¶
Data is sent to the server from the client only with specific HTTP methods
(usually, these are POST
, PUT
and PATCH
for basic HTTP). Clients
are required to include a Content-type
header in these requests,
specifying the mimetype of the data sent.
When a request arrives at a ContentNegotiationMixin
derived Blueprint
, its Content-type
-header is matched
against any incoming
type. If
it does not match any of the types registered there, an
UnsupportedMediaType
exception is thrown (and
returned to the client, see Outgoing content for a description on how it
will serialized).
If a client does not send a Content-type
-header along with the contents,
an UnsupportedMediaType
exception is thrown as
well. If there is no content, the Content-type
-header is ignored.
Afterwards, the requests is processed as normal and passed on to a view.
Outgoing content¶
Flask-arrest does not alter responses automatically, but provides facilities to do so. These are concentrated in the following two helper functions:
-
flask_arrest.helpers.
get_best_mimetype
()¶ Returns the highest quality server-to-client content-type that both agree on. Returns
None
, if no suitable type is found.Internally, works by querying the blueprint for its
outgoing
attribute and comparing it with theAccept
-headers sent by the client..
Normally, you will not need to call
get_best_mimetype()
directly, instead
interact
with the following function:
-
flask_arrest.helpers.
serialize_response
(response_data, content_type=None, status=200, renderer=None)¶ Serializes a response using a specified renderer.
This will serialize
response_data
with the specifiedcontent_type
, usingrenderer
.If
content_type
isNone
,get_best_mimetype()
will be used to determine a suitable type. If no match is found, aNotAcceptable
exception is thrown.If no render is supplied, use the blueprint’s
content_renderer
.Parameters: - response_data – Data to be serialized. Can be anything the renderer can handle.
- content_type – The
Content-type
to serialize for. - status – The response status to pass on to the renderer.
- renderer – The renderer to use. If
None
, lookup the current blueprint’scontent_renderer
.
Returns: A
Response
object.
Any data that a view might want to return is simply passed on to
serialize_response()
and the result
returned.
Content-negotiation API reference¶
-
class
flask_arrest.
ContentNegotiationMixin
(*args, **kwargs)¶ A blueprint mixin that supports content negotiation. Used in conjunction with the
get_best_mimetype()
andserialize_response()
functions.incoming
types are checked whenever a client sends a request with content to this blueprint. If the suppliedContent-type
-Header is not among the MIME-Types valid for the specific endpoint, the request is rejected with aUnsupportedMediaType
exception.outgoing
types supply information about which possible mimetypes can be sent back to the client. Renderers for data can use these to find an intersection with theAccept
-headers the client sent. Many will send an HTTP 406 (Not Acceptable) error if none of the advertised types is found in the clientsAccept
-header.
-
class
flask_arrest.helpers.
MIMEMap
¶ Special datastructure that maps an endpoint to a set of mimetypes. The default set of mimetypes for any endpoint is
{None}
.A value of
None
will be replaced with all mimetypes set for the special endpointDEFAULT_ENDPOINT
.If
None
is not included in a specific endpoints set of mimetypes, it will not include the defaults mentioned above.Note that endpoint names should usually be added without the Blueprint-prefix (i.e. “index” instead of “api.index”).
-
DEFAULT_ENDPOINT
= None¶ The default endpoint. Any value of
None
in the set of acceptable types in other endpoints will be replaced with all types assigned to this endpoint.
-
add_mimetype
(mimetype, endpoint=None)¶ Adds a mimetype to an endpoint.
-
get_mimetypes
(endpoint=None)¶ Get all mimetypes for an endpoint.
-
set_mimetypes
(mimetypes, endpoint=None)¶ Sets all mimetypes for an endpoint.
Note that if you exclude
None
from themimetypes
set, the mimetypes set forDEFAULT_ENDPOINT
will not be applied. This allows specifying an endpoint that does not handle all of the otherwise common mimetypes.
-
-
flask_arrest.helpers.
serialize_response
(response_data, content_type=None, status=200, renderer=None) Serializes a response using a specified renderer.
This will serialize
response_data
with the specifiedcontent_type
, usingrenderer
.If
content_type
isNone
,get_best_mimetype()
will be used to determine a suitable type. If no match is found, aNotAcceptable
exception is thrown.If no render is supplied, use the blueprint’s
content_renderer
.Parameters: - response_data – Data to be serialized. Can be anything the renderer can handle.
- content_type – The
Content-type
to serialize for. - status – The response status to pass on to the renderer.
- renderer – The renderer to use. If
None
, lookup the current blueprint’scontent_renderer
.
Returns: A
Response
object.
-
class
flask_arrest.
RestBlueprint
(*args, **kwargs)¶ A REST Blueprint.
-
content_renderer
= None¶ The content renderer to use as the default. Usually called by
serialize_response()
, should support theRenderer
interface.Per default, a copy of
content_renderer
is used as the initial value.
-
exception_renderer
= None¶ The exception renderer that is used to render every
HTTPException
thrown inside this blueprint. Should support theRenderer
interface.
-
http_errorhandlers
(f)¶ Decorator for registering a function as an exception handler for all instances of
HTTPException
.This function will go away as soon as the following issue in flask is fixed: https://github.com/mitsuhiko/flask/pull/952
-