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:
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.