There’s more than GET and HEAD requests. To be a useful web library you better support POST, PUT, PATCH and DELETE as well, and so does liberator. While there are even more HTTP methods than those, liberator has no out-of-the-box support for them and treats them like GET requests. In any case you need to declare them as known and allowed.
The allowed methods are determined by :method-allowed?
. The
default implementation for this decision uses the resource key
:allowed-methods
to obtain a list of methods and checks if it
matches the request method. When adding more methods to your resource,
make sure that the method is declared as known in
:known-methods
. By default, liberator knows the methods from
RFC2616: GET, HEAD, PUT, POST, DELETE, OPTIONS, TRACE as well as PATCH
from RFC5789 (since version
0.12).
Post requests share a lot of the decision flow with GET requests. The
main difference is that you can also reach the handlers
:created
, :no-content
and :see-other
. Because
post is a non-idempotent method, you can provide a function for the
key :post!
which is optimal for changing the state on the
server. The negotiation of the status code is done afterwards. For the
details please refer to the decision graph.
An idiomatic way to support post is the following:
We can extend this example to support conditional request. Thus a client can make sure that the POST is enacted only if no other request was made since it checked the resource:
We also make a little resource to retrieve the posted content again:
A quick test with curl shows that we cannot post to a stale resource:
The necessary steps to implement handling of PUT are mostly those for
POST. A key difference is that :can-put-to-missing?
can lead
to :conflict?
which can send you to :handle-conflict
.
This is not possible for POST requests. On the other hand PUT to a
nonexistent resource does not allow a response that sends you to a
different location. The necessary flow can be seen as always on the
decision graph.
The PATCH method is similar to PUT except that the entity contains a list of differences between the original version of the resource identified by the Request-URI and the desired content of the resource after the PATCH action has been applied. The list of differences is in a format defined by the media type of the entity (e.g., “application/diff”) and MUST include sufficient information to allow the server to recreate the changes necessary to convert the original version of the resource to the desired version.
A rudimentary way to support patch follows:
Values specified by :patch-content-types will be returned as part of the Accept-Patch header in an OPTIONS request response for the resource.
In practice, one is more likely to implement the patch method using a more formalized method of describing changes between documents. If one is managing data in an XML format, perhaps XSLT can be used to describe the set of changes.
A more web friendly approach can be taken if the data is represented as JSON. A simple library to handle JSON diff and patch can be found at https://github.com/daviddpark/clj-json-patch, which was put together to meet a need of handling patch requests with liberator.
Continue with Putting it all together.