Applying HATEOAS to a REST API with Spring Boot

HATEOAS is an acronym for Hypermedia As The Engine Of Application State. Even after expanding that for you it still might not mean a lot. HATEOAS is an extra level upon REST and is used to present information about the REST API to the client, allowing for a better understanding of the API without the need to bring up the specification or documentation. This is done by including links in a returned response and using only these links to further communicate with the sever. This reduces the likely hood of the client breaking due to changes to the service. If there are some static endpoints that the client can make use of and further calls are done via the links included in the response, the client’s code should not break (I am not claiming it is 100% safe). This makes the assumption that the links returned with the response have already implemented the standard REST verbs, lets face it, it would be pretty silly to link to an endpoint that isn’t actually there. This post will go through how to implement HATEOAS Rest service using Spring Boot.

As always lets start out by looking at the dependencies that are required (Lombok + MySQL dependencies have been used but not shown below). spring-boot-starter-hateoas contains the spring-boot-starter-web dependency so you do not need to include that like you probably would when creating a REST API with Spring Boot.

It is also worth noting that spring-boot-starter-parent version 2.0.0.M3 has been used in this post.

Now that we have got the dependencies out of the way, I think the first piece of code we should look at is a cut down version of a rest controller that has implemented HATEOAS.

The reason I cut out a lot of the code in this example is so we can look at individual parts without to much noise. So what have we got above? A basic REST service with the rest verbs GET, POST, PUT and DELETE implemented along with a retrieve all method. Each endpoint returns a ResponseEntity with most of them (not DELETE) containing a PersonResource / Resources<PersonResource>. This is where the HATEOAS service differentiates from the standard REST service which would normally return the ResponseEntity containing the object (or the object directly) instead of this resource object. In this scenario it returns ResponseEntity<PersonResource> (HATEOAS) instead of ResponseEntity<Person> (REST).

So what is this resource object I keep mentioning? It is simply a wrapper that contains both the object you would normally return plus URIs (links) to related endpoints that can be used. One way to make this seem a bit clearer is that the PersonResource shown in the above example could also be written as Resource<Person> where Person is the object you would normally return. Below is JSON would be returned from a GET request to a standard REST service followed by the output of a HATEOAS service for the same call.

CURL localhost:8090/people/1

REST service

HATEOAS serivce

As you can see there is a lot more going on in the HATEOAS response due to all the links that have been included. The URIs in this example might not be the most useful, but should hopefully demonstrate the idea well enough. From the original request that was made you have links showing where to retrieve all people and all the memberships for this person and finally a “self” link pointing back to the request that was just made. Now that we have a better idea of what the resource object is we can have a look at how PersonResource is implemented.

Theres not much to this class as it only consists of a constructor with the rest of the methods and functionality it needs being provided by ResourceSupport. There are two things that happen here, the object that is to be returned is stored with a getter being created (done by Lombok here) and links to related resources are created. Lets break down one of the lines of code that adds a link to the resource to see what is happening.

add is a method inherited from ResourceSupport which adds the link passed to it. linkTo creates the link and methodOn gets the URI for the GymMembershipController.all method (people/{id}/memberships), both of these methods are static methods from ControlLinkBuilder. The id has been passed into the all method allowing the {id} in the URI to be replaced by the input value. Once the link is created withRel is called to provide a name to the to describe how it is related to the resource. The other lines go about creating links in slightly different ways, one manually creates a new Link object and another uses withSelfRel which simply names the relation as “self”.

Now we have a better understanding of what a resource is we can look at the actual code inside the controller methods, hopefully I have chosen the correct response codes otherwise I am sure someone will try and correct me… I will then go on to explain two of them in more depth as same concept runs through them all.

We are going to look at the all method first.

This method makes use of the Resources object to return a collection of (you might of guessed it!) resources, in this case a collection of PersonResource. Just like the construction of the PersonResource earlier, Resources can also have links added to it. In this example a reference of “self” has been added which has been built using the ServletUriComponentsBuilder. fromCurrentRequest is nice enough to know what request has been made and because this request has been made to retrieve all people, it does not require any extra information. The URI that is then built and the string output created is used in a new Link and passed into the ResponseEntity. Everything went ok so a response code of 200 ok was used.

The following request produces the JSON output.

CURL localhost:8090/people

Note how each person still has their links tied to them as well as the link related to the collection (the Resources object). Now onto the post method.

The first thing this method does is create a new version of the Person object, preventing the client from persisting data that the service does not want saved initially (such as the id). The constructor I used in this example was made for convenience, but for clarity it sets all values except for the it’s id. After the data is persisted a URI needs to be created to be passed into the ResponseEntity. This is done slightly differently from the previous example as the URI is created for the persisted data. Therefore a URI that represents a GET request is put together using the MvcUriComponentsBuilder. fromController gets the URI to the controller, appends the path of /{id} onto the end of it and using the buildAndExpand method replaces the path variable of {id} with the person’s id. The created URI is then used with a 201 Created code and a new PersonResource is made.

The following request produces the JSON output.

CURL -X POST localhost:8090/people 
-H "Content-Type: application/json" 
-d '{"firstName":"test",
     "dateOfBirth":"01/01/0001 01:10", 
     "profession":"im a test", 

So there we have it, HATEOAS (Hypermedia As The Engine Of Application State) is built upon a REST API to further decouple the client from the server by decreasing the number of hard coded endpoints that the client can access. Instead they are called via links inside resources that are returned by the static endpoints that the server provides. This also decreases the chance of the client breaking when the service changes as it relies of the names of the links rather than their URIs. As always Spring Boot comes equipped with everything we need to get up and running with reasonable speed, assuming the spring-boot-starter-hateoas is included of course! On a closing note, whether or not HATEOAS is worth including with a REST API still seems to be up for discussion due to the complexity it adds when designing the service and because it requires the client to be written differently when compared to one that makes requests to a standard REST service. That being said, whether you decide it’s worth using or not, at least you now have an understanding in how to create one with Spring Boot!

The code used in this post can be found on my GitHub.

  1. Hi Dan. Thanks for sharing.
    One question: What’s the point of the person-id link? What is it meant to be used for?



    1. Hi Stefan,

      Thanks for the comment, after reviewing what you have just asked I have realised that I made a mistake including the person-id and I will remove it from the post!

      To answer your question, it is used for nothing which is why it should be removed 🙂




  2. Hi
    Thanks for this article. It’s really useful.
    Did you happen to write a client app for this server app?
    I’m struggling with it and would be happy to have some input.



    1. Hi Douglas,

      I did not write/use a client when testing this code (just used curl/postman).

      From what I understand to create a client that uses HATEOAS you use the object stored in the resource to display data onto the screen (so the “person” object in the JSON response) and the links to generate buttons. The buttons only exist when the reference to the link exists (for example the “memberships” ref), if the reference is there then take its value (the link) and use it as the buttons action.

      If it is something that you wish to test (I have not tried this personally) you can use the spring-data-rest-hal-browser dependency which will provide you with a premade HAL browser that can make requests and receive responses. The post here use-hal-browser-spring-data-rest-springboot-mysql provides some information on using it.

      Hopefully this helps you out!




  3. […] I have written recently relating to writing a HATEOAS service and handling exceptions with Spring (Applying HATEOAS to a REST API with Spring Boot and Global exception handling with @ControllerAdvice). Now that we have looked through setting up a […]



  4. […] I like Dan’s post that introduces the concepts of hypermedia and HATEOAS, in particular, and does so with some sample code based on Spring Boot and Spring HATEOAS. […]



  5. […] via Applying HATEOAS to a REST API with Spring Boot — Lanky Dan Dev Blog […]



  6. Mohamed Mauroof June 25, 2018 at 9:01 am

    Hi Dan, Great article,
    I would like to see how you would handle the memberships relationship while posting the person JSON. I have another implementation of my own domain where I created a many to many relatioship between Employee and Club. Im trying send a post request to the employee endpoint where I have an employee object with the list of URIs pointing to club resource. My JSON looks like this;

    “firstName”: “Stephen”,
    “lastName”: “Hawking”,
    “clubs”: [

    But the request fails with the following error.

    Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.demo.hateoas.example.Club` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (‘http://localhost:8080/clubs/1’); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.demo.hateoas.example.Club` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (‘http://localhost:8080/clubs/1’)

    How to fix this problem?



    1. Hi Mohamed,

      Glad you liked the post.

      If I understand you problem correctly, the issue is that the club you have included in your post should still be an actual Club object and not a link. It looks like it’s failing trying convert the URL into a Club instance.




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: