Content Negotiation

A key feature of hypermedia is the ability for the client to request the response in a particular format and for the server to respond to that – and several other – formats as necessary. For example, a client could request the response come back formatted as XML, typically by specifying that in the “Accepts” header by using the standard XML MIME-type string “text/xml”. If the server doesn’t support XML as a response format, it should send back an HTTP error code “406 Not Acceptable”.

Simply specifying XML as a return format, however, doesn’t really do much to help the client figure out what the XML contains. The XML spec overcomes this by adding a DTD element in the response body that links to a document that helps the client interpret the response. Other response types like JSON do not currently have a well- specified way to do this and rely, instead, on either the Accepts and Content-Type headers or in using a file extension to allow the client developer to specify the preferred response format.

Using the content headers allows for more fine-grained control over the negotiation process, allowing the client to specify not just the high-level format – i.e. JSON or XML – but the actual profile that governs the layout, including the version.

This specification may follow an existing or emerging standard, such as can be found on Schema.org, or may be specified by the API producer. This allows for a great deal of flexibility for the API producer to define responses that best match the structure and needs of their API.

For example, an e-commerce API provider may choose to create their own profile for a product in their catalog which best mirrors how a product is represented elsewhere in their application. This profile will likely be used where a product is referenced in a system, so the application developers should standardize internally on a specific profile, providing it a custom MIME type:

application/json;vnd.example.products.json+v1

Note the use both of the representational format (“json”) and the version (“v1”). This form of content negotiation allows versioning at the individual resource level, which can help keep the codebase that drives the application clean and consistent while allowing for increased flexibility to iterate. If the client application sets the Accept header to “*/*” or leaves it out completely, the API may return its preferred representational format, which, in the above case, will likely be the most recent version of the custom Product representation.

4 thoughts on “Content Negotiation”

  1. So I’ve seen other formats for `Accept:` and `Content-Type:` headers that look more like `vnd.example.products+json;v=1`. From the W3C spec, I can see that this is using an `accept-param` for the version, but that only looks like it’s valid for `Accept:`. And it looks like the `+json` is conventional only?

    Am I over-analyzing, or are there semantic differences here?

  2. So I’ve seen other formats for Accept: and Content-Type: headers that look more like vnd.example.products+json;v=1. From the W3C spec, I can see that this is using an accept-param for the version, but that only looks like it’s valid for Accept:. And it looks like the +json (or your +v1) is conventional only?

    Am I over-analyzing, or are there useful semantic differences here?

    1. Hmm. Just found this in RFC-6838, describing use of the ‘+’ suffix, and this describing +json and others. The former would seem to indicate that using unregistered suffixes may not be a good idea. If standards matter, anyway. 🙂

  3. Agree. Versioning should refer to responses, not endpoint structure. A change to an endpoint is a re-design of the business model all together (either because the business actually changed or the first iteration of the URIs were not correct and are being re-deployed). If a URI is aligned with the business model and goals of the API, then that URI of a resource should not change….however, the representation of a resource certainly can change as the business introduces new attributes, translations, etc.. Having the version identified as an attribute of the expected content format is spot on.

Leave a Reply

Your email address will not be published. Required fields are marked *