HTTP has provisions for several mechanisms for “content negotiation” - the process of selecting the best representation for a given response when there are multiple representations available. — RFC 2616, Fielding et al.
How content negotiation works
REST framework uses a simple style of content negotiation to determine which media type should be returned to a client, based on the available renderers, the priorities of each of those renderers, and the client’sAccept: header. The style used is partly client-driven, and partly server-driven.
Priority rules
- More specific media types are given preference to less specific media types
- If multiple media types have the same specificity, then preference is given based on the ordering of the renderers configured for the given view
Example
Given the followingAccept header:
application/json; indent=4(most specific)application/json,application/yaml, andtext/html(equal specificity)*/*(least specific)
renderer_classes list or DEFAULT_RENDERER_CLASSES setting.
For more information on the HTTP Accept header, see RFC 2616.
“q” values are not supported“q” values are not taken into account by REST framework when determining preference. The use of “q” values negatively impacts caching, and in the author’s opinion they are an unnecessary and overcomplicated approach to content negotiation.This is a valid approach as the HTTP spec deliberately underspecifies how a server should weight server-based preferences against client-based preferences.
Built-in Content Negotiation Classes
BaseContentNegotiation
rest_framework.negotiation.BaseContentNegotiation
All content negotiation classes should extend BaseContentNegotiation and override the .select_parser() and .select_renderer() methods.
Methods
Given a list of parsers and a media type, return the appropriate parser to handle the incoming request.Arguments:
request- The incoming request objectparsers- List of parser instances
- A parser instance from the list, or
Noneif none can handle the request
Given a request and a list of renderers, return a two-tuple of (renderer, media type).Arguments:
request- The incoming request objectrenderers- List of renderer instancesformat_suffix- Optional format suffix from the URL
- A two-tuple of
(renderer, media_type), or raisesNotAcceptableexception
DefaultContentNegotiation
rest_framework.negotiation.DefaultContentNegotiation
The default content negotiation class used by REST framework.
Attributes
Reference to REST framework settings
Parser selection
Theselect_parser() method iterates through the available parsers and returns the first parser that matches the request’s Content-Type header.
Renderer selection
Theselect_renderer() method examines the Accept header and available renderers to determine which renderer to use for the response.
The method implements the following logic:
- Check for format suffix or format query parameter override (e.g.,
?format=json) - Parse the
Acceptheader into a list of media types - Order media types by precedence (specificity)
- Iterate through media types and renderers to find the best match
- Return the renderer and accepted media type, or raise
NotAcceptable
Methods
If there is a format suffix (e.g.,
.json), filter the renderers to only those that accept that format.Arguments:renderers- List of renderer instancesformat- The format string (e.g.,'json','html')
- Filtered list of renderers, or raises
Http404if no renderers match
Given the incoming request, return a tokenized list of media type strings from the
Accept header.Arguments:request- The incoming request object
- List of media type strings (defaults to
['*/*']if no Accept header)
Configuration
Setting content negotiation globally
The default content negotiation class may be set globally using theDEFAULT_CONTENT_NEGOTIATION_CLASS setting:
Setting content negotiation per-view
You can also set the content negotiation used for an individual view or viewset using thecontent_negotiation_class attribute:
Custom Content Negotiation
It’s unlikely that you’ll want to provide a custom content negotiation scheme for REST framework, but you can do so if needed. To implement a custom content negotiation scheme, overrideBaseContentNegotiation.
REST framework’s content negotiation classes handle selection of both the appropriate parser for the request and the appropriate renderer for the response, so you should implement both the .select_parser(request, parsers) and .select_renderer(request, renderers, format_suffix) methods.
Example: Ignore client preferences
The following is a custom content negotiation class which ignores the client request when selecting the appropriate parser or renderer:Example: Custom media type matching
Here’s a more sophisticated example that implements custom media type matching logic:Using custom content negotiation
Once you’ve defined a custom content negotiation class, you can use it in your views:Format Suffixes
REST framework supports format suffixes (e.g.,.json, .html) as a way to explicitly request a particular representation. Format suffixes override the Accept header during content negotiation.
Enabling format suffixes
You can enable format suffixes in your URL configuration:GET /users/(uses Accept header)GET /users.json(forces JSON response)GET /users.html(forces HTML response)
Query parameter format override
You can also use a query parameter to specify the format:URL_FORMAT_OVERRIDE setting:
None to disable query parameter format overrides:
Related Settings
URL_FORMAT_OVERRIDE
The query parameter name that can be used to override the format. Set to
None to disable query parameter format overrides.DEFAULT_CONTENT_NEGOTIATION_CLASS
The default content negotiation class to use.
Media Type Matching
Content negotiation uses media type matching to determine which parser or renderer to use. The matching algorithm considers:- Main type and subtype -
application/jsonvstext/html - Wildcard matching -
*/*matches anything,text/*matches all text types - Parameters -
application/json; indent=4includes parameters
Specificity rules
More specific media types take precedence:application/json; indent=4(most specific - includes parameters)application/json(specific main type and subtype)application/*(specific main type, wildcard subtype)*/*(least specific - matches everything)
Example matching
Content Type vs Accept Header
Content-Type header (request)
TheContent-Type header specifies the media type of the request body:
Accept header (response)
TheAccept header specifies what media types the client can handle in the response:
Example
- Request parsing: Uses
JSONParser(based onContent-Type) - Response rendering: Uses
TemplateHTMLRenderer(based onAccept)
