negotiation - Content negotiation

Content negotiation is the process of selecting an appropriate representation (e.g. JSON, HTML, etc.) to return to a client based on the client’s and/or server’s preferences.

If no custom renderers are supplied, this plugin will render responses to JSON.

import asyncio

from aiohttp import web
from aiohttp_utils import negotiation, Response

async def handler(request):
    return Response({'message': "Let's negotiate"})

app = web.Application()
app.router.add_route('GET', '/', handler)

# No configuration: renders to JSON by default
negotiation.setup(app)

We can consume the app with httpie.

$ pip install httpie
$ http :5000/
HTTP/1.1 200 OK
CONNECTION: keep-alive
CONTENT-LENGTH: 30
CONTENT-TYPE: application/json
DATE: Thu, 22 Oct 2015 06:03:39 GMT
SERVER: Python/3.5 aiohttp/0.17.4

{
    "message": "Let's negotiate"
}

Note

Handlers MUST return an aiohttp_utils.negotiation.Response (which can be imported from the top-level aiohttp_utils module) for data to be properly negotiated. aiohttp_utils.negotiation.Response is the same as aiohttp.web.Response, except that its first argument is data, the data to be negotiated.

Customizing negotiation

Renderers are just callables that receive a request and the data to render.

Renderers can return either the rendered representation of the data or a Response.

Example:

# A simple text renderer
def render_text(request, data):
    return data.encode(request.charset)

# OR, if you need to parametrize your renderer, you can use a class

class TextRenderer:
    def __init__(self, charset):
        self.charset = charset

    def __call__(self, request, data):
        return data.encode(self.charset)

render_text_utf8 = TextRenderer('utf-8')
render_text_utf16 = TextRenderer('utf-16')

You can then pass your renderers to setup with a corresponding media type.

from collections import OrderedDict
from aiohttp_utils import negotiation

negotiation.setup(app, renderers=OrderedDict([
    ('text/plain', render_text),
    ('application/json', negotiation.render_json),
]))

Note

We use an OrderedDict of renderers because priority is given to the first specified renderer when the client passes an unsupported media type.

aiohttp_utils.negotiation.setup(app: aiohttp.web.Application, *, negotiator: <built-in function callable> = <function select_renderer>, renderers: collections.OrderedDict = OrderedDict([('application/json', <JSONRenderer()>)]), force_negotiation: bool = True)[source]

Set up the negotiation middleware. Reads configuration from app['AIOHTTP_UTILS'].

Parameters:
  • app (Application) – Application to set up.
  • negotiator – Function that selects a renderer given a request, a dict of renderers, and a force parameter (whether to return a renderer even if the client passes an unsupported media type).
  • renderers (OrderedDict) – Mapping of mediatypes to callable renderers.
  • force_negotiation (bool) – Whether to return a rennderer even if the client passes an unsupported media type).
aiohttp_utils.negotiation.negotiation_middleware(renderers=OrderedDict([('application/json', <JSONRenderer()>)]), negotiator=<function select_renderer>, force_negotiation=True)[source]

Middleware which selects a renderer for a given request then renders a handler’s data to a aiohttp.web.Response.

class aiohttp_utils.negotiation.Response(data=None, *args, **kwargs)[source]

Same as aiohttp.web.Response, except that the constructor takes a data argument, which is the data to be negotiated by the negotiation_middleware.

aiohttp_utils.negotiation.select_renderer(request: aiohttp.web_reqrep.Request, renderers: collections.OrderedDict, force=True)[source]

Given a request, a list of renderers, and the force configuration option, return a two-tuple of: (media type, render callable). Uses mimeparse to find the best media type match from the ACCEPT header.

class aiohttp_utils.negotiation.JSONRenderer[source]

Callable object which renders to JSON.

json_module = <module 'json' from '/usr/lib/python3.5/json/__init__.py'>
aiohttp_utils.negotiation.render_json = <JSONRenderer()>

Render data to JSON. Singleton JSONRenderer. This can be passed to the RENDERERS configuration option, e.g. ('application/json', render_json).