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
outgoingattribute 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_datawith the specifiedcontent_type, usingrenderer.If
content_typeisNone,get_best_mimetype()will be used to determine a suitable type. If no match is found, aNotAcceptableexception 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-typeto 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
Responseobject.
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.incomingtypes 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 aUnsupportedMediaTypeexception.outgoingtypes 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
Nonewill be replaced with all mimetypes set for the special endpointDEFAULT_ENDPOINT.If
Noneis 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
Nonein 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
Nonefrom themimetypesset, the mimetypes set forDEFAULT_ENDPOINTwill 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_datawith the specifiedcontent_type, usingrenderer.If
content_typeisNone,get_best_mimetype()will be used to determine a suitable type. If no match is found, aNotAcceptableexception 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-typeto 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
Responseobject.
-
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 theRendererinterface.Per default, a copy of
content_rendereris used as the initial value.
-
exception_renderer= None¶ The exception renderer that is used to render every
HTTPExceptionthrown inside this blueprint. Should support theRendererinterface.
-
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
-