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.
By default, rendering the value returned by a handler according to content
negotiation will only occur if this value is considered True. If you want to
enforce the rendering whatever the boolean interpretation of the returned
value you can set the force_rendering
flag:
from collections import OrderedDict
from aiohttp_utils import negotiation
negotiation.setup(app, force_rendering=True,
renderers=OrderedDict([
('application/json', negotiation.render_json),
]))
-
aiohttp_utils.negotiation.
setup
(app: aiohttp.web_app.Application, *, negotiator: callable = <function select_renderer>, renderers: collections.OrderedDict = {'application/json': <JSONRenderer()>}, force_negotiation: bool = True, force_rendering: bool = False)[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 renderer even if the client passes an unsupported media type). - force_rendering (
bool
) – Whether to enforce rendering the result even if it considered False.
- app (
-
aiohttp_utils.negotiation.
negotiation_middleware
(renderers={'application/json': <JSONRenderer()>}, negotiator=<function select_renderer>, force_negotiation=True, force_rendering=False)[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 adata
argument, which is the data to be negotiated by thenegotiation_middleware
.
-
aiohttp_utils.negotiation.
select_renderer
(request: aiohttp.web_request.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 '/home/docs/.pyenv/versions/3.7.9/lib/python3.7/json/__init__.py'>¶
-
-
aiohttp_utils.negotiation.
render_json
= <JSONRenderer()>¶ Render data to JSON. Singleton
JSONRenderer
. This can be passed to theRENDERERS
configuration option, e.g.('application/json', render_json)
.