Hypermedia API implementation in Forest

In this post we will implement the bookshop example (outlined in Why hypermedia APIs) as a hypermedia API using the framework Forest. This is a very long post because it touches on most aspects of the framework. So if you don’t care about all the details you can skip to the evaluation and conclusion.

The complete code can be found here and a running example is available here.


Forest is an open source Java framework for writing hypermedia API:s. It is inspired by the REST framework implemented in the qi4j framework implemented by Rickard Öberg.

Resource Design

We will start by designing and implementing the resources needed for this domain. We have identified the following resources:

  • RootResource: the starting point for the API
  • BooksResource: a collection-like resource containing all the books in this book shop
  • BookResource: a representation of an actual book

Root Resource

The root resource is programmed as a class extending the Resource interface

public class RootResource implements Resource {


For now we want two methods one to log on to the site and one to go to the sub resource that lists all the books. Hence we add the following code:

   public void login( LoginDTO login ) {

   public Resource books() {
      return new BooksResource();

The contents of the login method is not shown because it is not relevant for this blog post. But now we have defined the wanted operations for the root resource.

Media types

Forest has built in support for the media types text/html and application/json. This means that before processing a request Forest will inspect the accept header and determine if is able to process the request. If the accept header is not one of the two supported types the response code 415 (Unsupported media type) is returned. Similarly for handling the return format the content-type header is used.

Loading the root URL in a browser gives the following result:



Sub Resources

The reason why HTML is returned is because the browser issues HTTP requests with accept headers with a preference for HTML. On the other hand if we use curl to de-reference the root URL the following is returned:

curl -H accept:application/json http://boiling-bayou-4189.herokuapp.com/bookshop/
{ "links": [{ "method":"POST",
            { "method":"GET",

We will focus on the HTML version for the rest of this blog post, but all resources detailed in HTML have a corresponding JSON representation.

Automatic Documentation

From the root URL we are able to follow the two links “login” or “books”. Where “books” just takes us to the list of books in the book shop, “login” is more interesting because we have a parameter “LoginDTO”. The class LoginDTO is shown below.

public class LoginDTO {

    private String username;

    public String getUsername() {
        return username;

    public void setUsername(String username) {
        this.username = username;

When following the “login” link we will be prompted with an HTML form as shown below.



This form is generated when Forest detects there is a mismatch between parameters needed and parameters supplied. So simply by using the API it will automatically tell you how to use it – automatic documentation!

Command/Query separation

Forest is opinionated and based on convention over configuration. So instead of using annotations such as @POST or @GET Forest uses Command/Query separation, meaning all operations are divided into two categories commands or queries.

  • A command cannot have a return value but is allowed to change the observable state of the application. Implemented as a void method. Called using POST.
  • A query must have a return value but must not change the observable state of the application. Implemented as a non-void method. Called using GET.

Method not allowed roundtrip

With the Command/Query separation in mind one might wonder how that is supposed to work in a web browser because following a link in a web browser is always using GET.

If we follow the “login” link and inspect the whole response we will notice the status code 405 is returned. Status 405 means method not allowed which is to say the URL used is correct but the HTTP verb used is incorrect. This matches what has just been described, i.e. login returning void means it is a command, which means it must use POST. The returned form is generated to match both the parameters needed and verb – in this case the LoginDTO and POST respectively.

Writing a username in the field and pressing submit should give a response string Operation completed successfully.


Once login is possible in the application the need for a logout operation arises. So in the RootResource class we can add a “logout” method as well:

  public void logout() {

These two opposite methods login and logout are also opposite when it comes to when they apply. If I am not logged in it does not make sense to log out only log in and vice versa. So what we would like is to only have login available when we are not logged in and only have logout available when logged in.

To achieve this Forest uses declarative constraints using annotations similar to Java Bean Validation (JSR 303). A constraint is an annotation with an Evaluator (a class that evaluates the constraint and returns either true or false) .

A LoggedIn constraint is implemented below:

public @interface LoggedIn {

    boolean value();

    class Evaluator implements ConstraintEvaluator {

        public boolean isValid( LoggedIn annotation, Resource resource) {
           // return true or false if logged in or not

This enables us to get the exact behavior we want. The root resource looks as follows (beautiful isn’t it?):

public class RootResource implements Resource {

    @LoggedIn( false )
    public void login( LoginDTO login ) {

    @LoggedIn( true )
    public void logout() {

    public Resource books() {
        return new BooksResource();


We saw previously that named sub-resources in Forest was done simply by creating a method returning a Resource instance in our case public Resource books(). But for the collection we would like the names of the child resources to be ids instead of names. For that Forest provides the following interface.

public interface IdResource extends Resource {
   public Resource id( String id);

Having a resource implementing this interface Forest will not expose a named sub-resource called id but rather delegate all segment names to the id method with the segment name passed as the id argument. For instance if /123/ was evaluated against a root resource implementing the IdResource interface the id method would be invoked with argument “123”.

So the first attempt to implement the BooksResource looks like this

public class BooksResource implements IdResource {

    public Resource id( String id ) {
        return new BookResource( id );

The BooksResource have a sub-resource method accepting the segment name as the book id. This id is used for constructing the BookResource representing the book with the given id. While this actually implements our model it is not very user friendly. The BooksResource has a characteristics of a collection but we only provide a method for looking up an actual element of the collection. What would be convenient for users of this book collection is a mechanism for traversing all the existing books, i.e. paging through the collection. For this purpose Forest provides the interface IdDiscoverableResource:

public interface IdDiscoverableResource extends IdResource {
    List discover();

IdDiscoverableResource extends the IdResource with a method returning links to its elements. The gory details of how to make pagination work is left out of this post so we will go ahead and return all the collection from this method. This enables us to implement the BooksResource as we want it:

public class BooksResource implements IdDiscoverableResource {

    public List discover() {
        List links = new ArrayList();
        for (Book book : BookRepository.findAll()) {
            links.add( new Linkable(book.getId(), book.getTitle()) );
        return links;

    public Resource id( String id ) {
    	return new BookResource( id );

Forest will recognize resources implementing IdDiscoverableResource so when rendering a representation of such a resource the result of invoking discover is included in the response. Below is shown the HTML representation of the BooksResource.



Sub Resources

Page 1 of 1 asc desc


The BookResource represents a single book and its constructor takes the id of the book as argument. The constructor has the responsibility to look up the book from the book repository and return appropriate error messages if something is wrong.

    private final Book book;

    public BookResource( String id) {
        book = BookRepository.get(id);
        if (book == null) {
            throw new NotFoundException( "No such book '" + id + "'");

First of all we would like some kind of description of the book like its author and title. This can easily be done by adding a query to the resource returning this meta data. However, it is typical to have this kind of meta data automatic be part of the book representation. To do this the interface ReadableResource should be extended.

public interface ReadableResource  extends Resource {
    T read();

When the framework renders a resource implementing this interface it will automatically include the contents of the read method in the representation.

The only thing left to do is to implement the two operations for purchasing and downloading the book. In order to purchase a book on this web site you must be logged in, not already have purchased the book, and supply your secret pin code (which is 1234 for all users). The first one is the LoggedIn constraint we saw earlier. The second one should also be implemented as a constraint since it controls enablement of a link, i.e. if you have not bought the book then show the link buy in the representation. So similarly as when we implemented the LoggedIn constraint we implement a HasBoughtBook constraint. Thirdly the pin code the must be supplied for the purchase is an argument of the buy method. In this example it is a simple DTO object holding a pin string. This gives us following signature of the buy and download methods.

    @LoggedIn( true )
    public void buy(PinDTO pin) {
        // validate pin and perform purchase

    @LoggedIn( true )
    public String download() {
        // return book content


With the above code snippets we have implemented the model as a hypermedia API so let’s take a step back and evaluate.


  • You get the discovery and documentation of the API for free. There is no extra work needed to get these nice properties
  • With the command/query separation and sub resources there is no need for protocol annotations such as @POST or @PATH. This gives us a non polluted code base
  • With the declarative constraints you can easily control the enablement of links in the representation. Having the constraints as annotations makes it easy to read the code and understand when an operation is available


  • The example implementation might seem impressive with very limited and clean code expressing exactly what is needed. This holds true as long as you stick with the simplest use cases and media types. The framework supports only very basic HTTP support
  • As with the media type support being hard coded to only JSON and HTML, the serialization is also hard coded. It would be nice to be able to plug-in you preferred serialization provider
  • What is easily supported by the framework in terms of linking is child linking. Creating operations or sub resources will all be children of the current resource making the resources structure a tree (this was one of the reasons for naming the framework Forest). The problem is that resources does not always form a tree but more often the more general structure called a graph. Forest has no easy mechanism to link to any non-child resource other writing the link in hand
  • The rel attribute is not supported. This is needed to provide semantic information to clients.

Other thoughts

  • Should probably use the standard Java Bean Validation instead of re-inventing the same thing
  • While convention over configuration greatly simplifies things, there should probably be a way to override the defaults. For example by allowing annotations for HTTP methods.


As we have seen this framework allows us to easily model the domain logic as a hypermedia API. We have been using it on several projects we have been working on and we believe that it contains many great ideas such as declarative constraints and default links included in representations. For simple domains where only the media type JSON is used by clients it might be OK. But as a general hypermedia API framework there needs to be better support for the HTTP protocol in general and be possible to extend with other media types as well.

This Post Has 4 Comments

  1. Nick Khamis

    How does the current implementation of JAX-RS 2,0, more specifically, JSR for RFC 5988 web linking change the playing field for Forest now.

    We are looking to increase our RS vocabulary by adopting HATEOAS however, would like to remain in the java “standard” world using JAX-RS 2.0. Could you please contact me by email if possible regarding this issue.

    Kind Regards.

    1. Mads Enevoldsen

      We are discussing the possibility of creating a real version of Forest as
      an extension to JAX-RS 2.0 (time restrictions has so far made the progress
      very limited). This seems very much in line with what you are planning to
      do, and I think that make very good sense.

      Web linking is very important to get correct, and Forest misses out on proper
      usage of the ‘rel’ attribute.

      You are very welcome to Skype/mail me with further questions.

    2. Jan Kronquist

      Although RFC 5988 is very useful in the sense that it describes the properties of a link, it is not sufficient to describe all links that you typically have in a HATEOAS API. This RFC only specifies how the Link header field should be used, which might be useful for behavioral links (eg buy book).

      However, by using something like HTML forms instead you can add templates for the data the must be provided by the consumer. This makes it much easier to test and also possible to change and add new fields without breaking existing clients.

      You also often want links embedded in your resources, for example between authors and their books. I call these navigational links and I see no point in repeating these in the Link header.

      All this limits the usefulness of the Link header (and RFC 5988). Unfortunately, JAX-RS 2.0 Link is only intended for Link headers (when serialized it is written as a Link header) which probably forces you to create your own Link representation for other types of links.

Leave a Reply