HTTP supports a rich set of methods to negotiate the representation of a resource. The client tells the server its preferences on media-type, character set, content encoding and language and the server uses this information to select the best representation available.
A typical use case with liberator is the support of multiple media types. Out of the box, liberator supports response generation for arbitrary clojure values such as JSON, clojure forms and some others. You can also return a String, File or InputStream from a handler which will be returned basically literally.
If you want to negotiate on the media type, then define the key
:available-media-types
which must return a list of the
supported media-type (or be a function which returns the list at
runtime). Liberator will then determine, based on this list and the
request header Accept
, which is the best media type available.
Liberator will store the media type in the representation map in the
context. This map is available in the context at the key
:representation
. You can use the values in any handler
function that is called after the media type was evaluated. This
is done in the decision called :media-type-available?
.
An example will illustrate how things fit together:
Let’s try some request
You can see that curl sent an Accept
header of “*/*” which means
that it accepts any media type. In this case, liberator will return
the first available media type.
Let’s try to be more specific and tell that we accept json and clojure but prefer clojure. (This was expected, right?)
You can see that we received a clojure representation. The representation was automatically generated by liberator from the clojure map that was returned from the handler method.
So, what happens if we request some media-type which is not available?
As you can guess, liberator will finally use
:handle-not-acceptable
to generate a 406 response:
If you watched closely then you observed that liberator automatically
returns a value for the Vary
header. The value of the header
is filled from the negotiated parameters in the representation map.
If you negotiated on e.g. media-type and language then it will be set
to Accept, Accept-Language
. The header is used by caching
proxies and caching user agents to tell apart different representation of
the same resource. Thus it is vital that it is set correctly. If not,
clients will receive cached values in the wrong media-type and worse.
Liberator supports negotiation for the headers Accept
(media-type),
Accept-Language
, Accept-Charset
and
Accept-Encoding
. The negotiated values are stored in the
representation map at the keys :media-type
, :language
,
:charset
and :encoding
.
If a handler returns a string for the representation then liberator
will return an inputstream for a bytestream representation of the
string in the negotiated character set. You can use (keys
(java.nio.charset.Charset/availableCharsets))
to obtain the
supported character sets on your platform.
The parameter :encoding
has no further support from liberator.
While content-encoding will typically be done by a reverse proxy in front
of your application, nothing prevents you to return a compressed
representation in the handler if requested.
Continue with Conditional Requests.