Content Negotiation is performed by an application in order :
Content-Type
of incoming data and deserialize it so the application can utilize it.Essentially, content negotiation is the client telling the server what it is sending and what it wants in return, and the server determining if it can do what the client requests.
Content negotiation validation in DotKernel API happens through middleware, and it ensures that the incoming request and the outgoing response conform to the content types specified in the config file for all routes or for a specific route.
It performs validation on the Accept
and Content-Type
headers of the request and response and returning appropriate
errors responses when necessary.
In DotKernel API the configuration file for content negotiation is held
in config/autoload/content-negotiation.global.php
and the array looks like this:
return [
'content-negotiation' => [
'default' => [
'Accept' => [
'application/json',
'application/hal+json',
],
'Content-Type' => [
'application/json',
'application/hal+json',
],
],
'your.route.name' => [
'Accept' => [],
'Content-Type' => [],
],
],
];
Except the default
key, all your keys must match the route name, for example in DotKernel API we have the route to
list all admins, which name is admin.list
.
If you did not specify a route name to configure your specifications about content negotiation, the default
one will
be in place. The default
key is mandatory
.
Every route configuration must come with Accept
and Content-Type
keys, basically this will be the keys that the
request headers will be validated against.
This specifies that your server can return that representation, or at least one of the representation sent by the client.
GET /admin HTTP/1.1
Accept: application/json
This request indicates the client wants application/json
in return. Now the server, through the config file will try
to validate if that representation can be returned, basically if application/json
is presented in the Accept
key.
If the representation cannot be returned, a status code 406 - Not Acceptable
will be returned.
If the representation can be returned, the server should report the media type through Content-Type
header of the
response.
Due to how these validations are made, for a
json
media type, the server can return a more generic media type, for example, if the clients sendAccept: application/vnd.api+json
and you configured yourAccept
key asapplication/json
the representation will still be returned asjson
.If the
Accept
header of the request contains*/*
it means that whatever the server can return it is OK, so it can return anything.
The second aspect of content negotiation is the Content-Type
header and determine the server can deserialize the data.
POST /admin/1 HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"foo": "bar"
}
The server will try to validate the Content-Type
header against your configured Content-Type
key from the config
file, and if the format is not supported, a status code 415 - Unsupported Media Type
will be returned.
For example, if you have a route that needs a file to be uploaded , normally you will configure the Content-Type
of
that route to be multipart/form-data
. The above request will fail as the client send application/json
as
Content-Type
.
If the request does not contain "Content-Type" header, that means that the server will try to deserialize the data as it can.
Request <-> Response
validationIn addition to the validation described above, a third one is happening and is the last one: the server will check if
the request Accept
header can really be returned by the response.
Through the way DotKernel API is returning a response in handler, a content type is always set.
This cannot be the case in any custom response but in any case the server will check what Content-Type
the response is
returning and will try to validate that against the Accept
header of the request.
If the validation fails, a status code 406 - Not Acceptable
will be returned.