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 the Accept-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 specified content_type, using renderer.

If content_type is None, get_best_mimetype() will be used to determine a suitable type. If no match is found, a NotAcceptable 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’s content_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() and serialize_response() functions.

incoming types are checked whenever a client sends a request with content to this blueprint. If the supplied Content-type-Header is not among the MIME-Types valid for the specific endpoint, the request is rejected with a UnsupportedMediaType 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 the Accept-headers the client sent. Many will send an HTTP 406 (Not Acceptable) error if none of the advertised types is found in the clients Accept-header.

incoming = None

a MIMEMap of incoming data types. The default will contain just application/json.

outgoing = None

a MIMEMap of outgoing data types. The default will contain just application/json.

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 endpoint DEFAULT_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 the mimetypes set, the mimetypes set for DEFAULT_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 specified content_type, using renderer.

If content_type is None, get_best_mimetype() will be used to determine a suitable type. If no match is found, a NotAcceptable 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’s content_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 the Renderer 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 the Renderer 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