5. Spring Hateoas
1. HATEOAS
Hateoas (Hypermedia as the engine of application state) is a RESTful API principle defined by Roy Fielding. It mainly means that, client can move by full application only from general ID URI's in hypermedia format. The principle implies that the API should guide the client through the application by returning relevant information about the next potential steps, along with each response.
For the connection between the server and the client, Fielding defines these four characteristics:
- Unique identification of all resources: all resources must be able to be identified with a URI (Unique Resource Identifier).
- Interaction with resources through representations: If a client needs a resource, the server sends it a representation (eg, HTML, JSON, or XML) so that the client can modify or delete the original resource.
- Explicit messages: each message exchanged between the server and the client must contain all the data necessary to understand each other.
- HATEOAS: This principle also integrates a REST API. This hypermedia-based structure makes it easy for customers to access the application, since they do not need to know anything else about the interface to be able to access and navigate through it.
HATEOAS is, in short, one of the most basic properties of REST APIs and as such, essential in any REST service.
A returned value without HATEOAS, with a client data:
Notice that:
- We have got all client data
- We don't know how to get data from specific related fields, like
DireccionorCuenta
The same request with HATEOAS:
As you can see:
- Only data from a client is sent
- We have links, with clear URI's to get specific information of that client
and most important If the server changes its structure, it will send updated links, and client will work without any problems
2. Adding HATEOAS
2.1. Libraries
Note
In this text, we are going to add HATEOAS capabilities to a RESTfull api developed along the unit.
We only need to add this dependency to our pom.xml, supposing we have use a spring starter project:
| XML | |
|---|---|
And it is done.
2.2. Wrappers
2.2.1. Starting point
Remember that we have done to our starter project:
- Model or DAO classes → prepared to save information in database. The are mapped with hibernate and are base for our repositories. For instance
Cliente - DTO classes → prepared to transfer data from and into our model.
- This class wraps the DAO (adding or removing fields).
- These classes have method to convert from/to between DAO and DTO.
- Is service who does the conversion
- Client will send us information in this DTO classes
- These classes can be use by either an API Rest or MVC web application.
2.2.2. HATEOAS wrapper
We need to define a new class to wrap our HATEOAS response.
Starting from DTO's, it contains all information from a class, own and related (Cliente plus Direccion plus Cuentas). With HATEOAS, as we showed recently, only need Cliente own information and need to generate links to related entities. Then we need to add to the client information the capability to generate and store links. The class that allow it is RepresentationModel<base_class> (full docs here). This will add to our classes:
- Structure to store links
- Methods to add, check and get links
The way to done it is:
Important
- As we have a base API rest working with
ClienteDTOwe have done this wrapper class from it. - Due to HATEOAS is only a response format, you can create it from
Clienteas base class, but you must define your service to returnClientetoo. - Very important to create a conversion method
fromClienteDTO2HATEOAS, staying for necessary fields.
Then, we will use add(Link) method in our ClienteHATEOAS wrapper to add as many Link is necessary.
3. Links
Now, the question is how to generate our Link objects in our wrapper classes. We could do it in a creative way, manipulating paths in strings and composing with complicated substring and concatenate methods.
But as we now what method is called to each reference, is better to create links obtaining references to the path from methods themselves. To do it, we must use these methods and static calls:
linkTo→ static method who creates aLinkfrommethodOn(class)→ search from a controller class for a method.methodName(args)→ get a real call for this method- And to label the link:
.withSelfRel()→ create a link calledself.withRel(String Link)→ create a link with given name.
Samples from our Cliente controller in next section
3.1. Self links
| Java | |
|---|---|
This sample:
- Loads a
ClienteDTOfrom currentClienteService. - Then looks in
ClienteControllerclass for a method calledshowClienteById. - Do an internall call and search for the path and bind argument to the path (do you remember
@PathVariable) - Finally, it gets the full path with argument and store in the Link with
selfreference
The result will be something like:
3.2. Reference links
| Java | |
|---|---|
This sample:
- Loads a
ClienteDTOfrom currentClienteService. - Then looks in
CuentaControllerclass for a method calledlistCuentasCliente. - Do an internall call and search for the path and bind argument to the path (do you remember
@PathVariable?) - Finally, it gets the full path with argument and store in the Link with
selfreference
The result will be something like:
3.3. Adding links to our wrapper and full sample
Once we have created links, we need to add to our last wrapper class. Simply we will use add() method to do it. In next method it receives a ClienteHATEOAS wrapper (with only data from ClienteDTO) and add as many links as we want:
The controller method to get a Cliente will be (commented):
and the result si something like:
4. Pending work
Now, getting a simple Cliente request you have access to all information and further actions can be taken based on the metadata in the response representation.
This allows the server to change its URI scheme without breaking the client. Also, the application can advertise new capabilities by putting new links or URIs in the representation.
You are invited to complete the project develop in class adding necessary wrapper and adding HATEOAS models.