Knowing how to handle different request methods and the extension
points for a liberator resource is one thing, putting all together in
a un-complected way is not trivial. Fortunately it’s not hard either
as the following example shows.
Handling a collection of resources
A typical model when you want to make some entities available is to
use one resource for the collection of entities and a second resource
which represents a single entity. This maps perfectly with the
semantics of GET, PUT, POST and DELETE:
Resource
Method
Comment
list
GET
List of entities
list
POST
Create new entity
entry
GET
Get entity
entry
DELETE
Delete entity
entry
PUT
Replace entity
List resource
The list resources accept and produces application/json in this
example. The body is parsed in :malformed and stored in the
context under the key ::data. To keeps things simple
post! generates a random number for the id and stores id under
:id. We enable redirect after post and :location picks
up the id to create the url where a resource for the created entity
can be found.
In case of a GET we return a simple list of URLs pointing to resources
for all entries.
First come some helper functions which might some day find their way
into liberator.
Then comes the resource for the list of entries.
Entry resource
The entry-resource implements access to a single entry. It supports
GET, PUT and DELETE. Like the list-resource it accepts json for update
and generates a json response.
An entries exists if the stored value is not nil. If the stored value
is nil, the entry is gone (status 410). If there is no value stored
at all, the entries does not exist (status 404).
On delete, the entry is set to nil and thus marked as gone.
Put requests replace the current entry and are only allowed if the
entries exists (:can-put-to-missing). The function for
:handle-ok might surprise at first sight: the keyword
::entry is used as a function and will lookup itself in the
context.
Here we use the syntax to define parametrized resources:
(defresource entry-resource [id]), these go
hand-in-hand with compojure’s routing parameters:
Sample curl session:
Possible extensions
This example is far from being feature complete. It can be extended
to support conditional requests and more media types. You can use
authorized? to restrict access to the resources.