In my previous article announcing my PHP framework Aphiria, I talked a lot about content negotiation, but not everyone really understand just what that is, why it helps you build more developer-friendly APIs, and how Aphiria makes it simple. So, let me explain. Content negotiation is how the client (usually a browser) and the server (your API) communicate the type of content in a request body as well as what type of content the client can accept in the response body. This process is formalized in RFC 2616 section 12, which I read through so you don’t have to.
Let’s look at a simple example request:
In human, this request is saying
“I’m creating a user with a UTF-8-encoded JSON body written in American English. I will accept JSON back, but I’ll settle for XML if you can’t send JSON. Likewise, I prefer American English, but will settle for any English dialect, and prefer UTF-8, but will accept UTF-16, too. Finally, here’s that JSON-encoded user I want to create.”
When the server receives this request, it scans the
Encoding headers to understand the content sent in the request. If it is able to handle the content type, it will deserialize the request body using the request headers. If it cannot, a 415 “Unsupported Media Type” response will be returned.
Where does the negotiation happen?
The negotiation happens when trying to determine the format to send back. In the above example, the server will look at the
Accept* headers, and will try to best accommodate the client’s preferences as long as the server also supports sending that type of content back. Let’s say the server couldn’t write JSON for some reason, but did support XML, it would serialize the response body to XML:
The client could then look at the
Content-* response headers to help deserialize the response body correctly.
What happens if the server cannot accommodate the client?
It depends — you could either return a 406 “Not Acceptable” response, or, if you’re like most frameworks, you’ll send back a response in a conservative format, eg JSON, as a last-ditch effort to complete the transaction.
Is that it?
For the most part, yes. There are more advanced ways of specifying preference using a quality
In this case, the client is specifying a preference (between 0 and 1, 0 meaning “I don’t want this at all” and 1 meaning “I want this the most”) for the response content type. In human, the client is saying
“Here’s UTF-8-encoded JSON, and all I want back is JSON — I do not want XML at all.”
Similarly, you can customize your negotiation to use things besides headers, eg query string parameters, although this isn’t strictly following the spec:
OK, I get it, but why should I care?
Content negotiation is the best way to serve up responses that your client will be happy with, creating a better developer experience. For example, some people despise XML, and would prefer JSON. If you use a framework such as Aphiria, you can accommodate that preference without any code on your part.
- No trying to manually deserialize multiple content types in your controllers
- No base classes you have to extend to take advantage of automatic (de)serialization
if/elsebranches in your controllers to handle serializing multiple content types in your responses
Just specify the POPO model you’d like to deserialize the request body to and the object you’d like to serialize in the response body. That’s it.
Even in the case of an unhandled exception, Aphiria will attempt to negotiate a problem details response for you.
Can I customize content negotiation in Aphiria?
Absolutely. Aphiria provides sensible defaults out of the box in the skeleton app, but if you’d like to customize anything, you may.
- Character encoding matcher — implement
- Language matcher — implement
- Supported languages — update
supportedLanguagesin your config
- Media type formatter matcher (how we choose the best (de)serializer) — implement
- Custom media type formatter (the (de)serializer for a specific content type) — implement
To actually set up your content negotiator to use your custom logic, just update the relevant properties in your config.
Where do I go from here?
Consider installing Aphiria and taking content negotiation for a spin. Its simplicity and customizability make developing REST APIs a cinch.