Hypermedia REST API using Spring HATEOAS

Hypermedia REST API using Spring HATEOAS

Representational state transfer (REST), a term coined by Roy Fielding in 2000, is a software architectural style that defines a set of constraints to be used for creating Web services. Web services that follow the REST architectural style are known as RESTful web services.

REST defines 6 architectural constraints, which the API should adhere to if it should be called as RESTful.

  1. Uniform interface – there should be an uniform way of interacting with a given server irrespective of device or type of application (website, mobile app).
    The four constraints for this uniform interface are:
    • Resource identification in requests
    • Resource manipulation through representations
    • Self-descriptive messages
    • Hypermedia as the engine of application state (HATEOAS)
  2. Client–server
  3. Stateless
  4. Cacheable
  5. Layered system
  6. Code on demand (optional)

Most API’s that call themselves REST can be said as RESTish, don’t implement the Hypermedia constraint. You can read more about Roy T. Fielding’s frustrations regarding that here.

These days, a lot of attention is given to generate a readable, simple URI for each service offered by the API. And you refer to the documentation to learn how to use the API, how to invoke it, what it expects, and what to expect back. The documentation is ill-maintained or at times non-existent. Swagger helps alleviate the documentation problem, but the server is still not free to make changes to the API. Any change will have an impact on the client and needs an update on its codebase.

Now consider the World Wide Web, where all the hypertext documents are interlinked by hyperlinks. The browser knows how to interpret the HTML document, create the links and the server is free to send any properly formed HTML without expecting the browser to make any changes to it. Hypermedia driven APIs offer a similar advantage where instead of referring to the API documentation, the client is able to figure out what the next actions are since each API response contains links to the next possible actions.

Consider that you are managing an e-commerce platform. You will probably have several endpoints that allow you to place an order, view the updates of your order, and cancel the order. If the order is not yet shipped, you may allow the user to cancel the order. And the UI will have to check a flag or make use of a service to determine if it can be canceled. With the Hypermedia design, your order response will have a link to cancel the order only if its possible to do so.

For example, if you look up the order details, response may look like below:

{
   "ordeer":{
      "id":"093b941d",
      "attributes":{
         "created_at":"2017-06-15 12:31:01Z",
         "paid_at":"2017-06-16 09:05:00Z"
      }
   },
   "links":{
      "cancel":"https://api.acme.com/orders/093b941d/cancel"
   }
}

The cancel link appears only when it’s possible to cancel the order.

In short, you are exposing state over HTTP now.

This is the main advantage of HATEOAS – you are not just adding links, but adding stateful links. They could be included based on the state managed by the business application or based on certain rules, workflows, etc.

Instead of providing unique id’s in the response, you provide URI’s and relations.

Do I need to care about building nice readable URI’s?

Not really! REST is an architectural style, not a protocol and it doesn’t enforce any URI style. With a hypermedia driven API, you define a relation between the links, and the client makes use of the rel attribute to determine how to move forward.

Why should I use HATEOAS?

  • Reduces coupling between server and client. The server is free to make changes to the API’s without letting the client know in advance. As long as the relations are defined properly, the client should be able to make use of them. The client is not expected to build the URL, instead, it follows the links.
  • Server controls the URL – this is critical especially when you have different types of clients. Instead of attempting to build the URL, they will figure it out from the resource representation.
  • Explorable API – for a developer, having an explorable API is a blessing. Clicking through the links may offer a better understanding of the API behavior.
  • Inline documentation – link relations can also embed or direct to the documentation for developers.

Why is it not used everywhere?

  • HATEOAS is a principle that hypertext should be the engine of application state, and the resource types should have embedded hyperlinks. These links can be used to access other resources. HATEOAS doesn’t offer a single standard to define how these links are expressed. It’s a guideline that allows you to use any standard that works for you.
    Needless to say, you have multiple standards available and frameworks around them.
  • People tend to use REST as a data-driven HTTP API without the Hypermedia subset because it’s easier to build that way. Adding HATEOAS introduces complexity on both server and client-side, but the benefits outweigh the complexity. If you are building an internal app that talks to another internal app, HATEOAS may not bring anything useful. But if you maintain a big application with multiple clients, you can’t really ask each of them to change the client code whenever the server changes something. HATEOAS allows you to evolve naturally without breaking the clients

Choosing a standard

You can represent your resource in any format – XML, JSON, plain text, etc. JSON is one of the most popular formats out there, but it has no built-in support for hyperlinks, which are a fundamental building block on the Web. Naturally, there are a number of formats that provide a standard based on JSON and allows you to build links in the response.

Some of the popular formats are:

There are several other formats available. This article offers a nice comparison between several of them.

Spring HATEOAS

The Spring HATEOAS project is a library of APIs that allows you to easily create REST representations that follow the principle of HATEOAS.

Spring HATEOAS provides abstractions that allow you to write code that is not tied to a specific standard. It supports multiple standards, and based on what the client asks for using the Accept header, it serves the response in the appropriate format. Alternatively, you can configure it to serve a specific format using an annotation too. If you need to switch the format, just update the annotation in the Configuration class and you are all set! Sweet!

Link

Spring HATEOAS lets create links through its immutable Link value type. Its constructor takes both a hypertext reference and a link relation, the latter being defaulted to the IANA link relation self.
Links can be used as below:

Link link = Link.of("/something");
assertThat(link.getHref()).isEqualTo("/something");
assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF);

link = Link.of("/something", "my-rel");
assertThat(link.getHref()).isEqualTo("/something");
assertThat(link.getRel()).isEqualTo(LinkRelation.of("my-rel"));

Representation model

To easily create hypermedia enriched representations, Spring HATEOAS provides a set of classes with RepresentationModel at their root. It’s basically a container for a collection of Links and has convenient methods to add those to the model. The models can later be rendered into various media type formats that will define how the hypermedia elements look in the representation.

A sample Representation Model class looks like below(examples from the Spring HATEOAS reference documentation):

class PersonModel extends RepresentationModel<PersonModel> {

  String firstname, lastname;
}

You can use the model as below:

PersonModel model = new PersonModel();
model.firstname = "John";
model.lastname = "Doe";
model.add(Link.of("https://hostname/person/123"));

If a client sends a request with Accept header as application/hal+json, the response will look as below:

{
  "_links" : {
    "self" : {
      "href" : "https://hostname/person/123"
    }
  },
  "firstname" : "John",
  "lastname" : "Doe"
}

For representing a single object, the convenience EntityModel type can be used. For collections, use CollectionModel object.

Building Links

Instead of manually building links, you can make use of the WebMvcLinkBuilder that lets you create links by pointing to controller classes as shown in the example below:

import static org.sfw.hateoas.server.mvc.WebMvcLinkBuilder.*;

Link link = linkTo(PersonController.class).withRel("person");

assertThat(link.getRel()).isEqualTo(LinkRelation.of("person"));
assertThat(link.getHref()).endsWith("/person");

You can also build links that point to methods or create dummy controller method invocations.

Link link = linkTo(methodOn(PersonController.class).show(2L)).withSelfRel();

assertThat(link.getHref()).endsWith("/person/2");

Affordances

The links that you add may be able to “afford” several other options too.

Spring HATEOAS provides an API to attach as many related methods(called Affordances) as needed to a link. For example, if you provide a link that allows the details of a user to be viewed, that link may afford an update or delete option as well.

Link findOneLink = linkTo(methodOn(controllerClass).findOne(id)).withSelfRel(); 

findOneLink //
          .andAffordance(afford(methodOn(controllerClass).updateEmployee(null, id))) 
          .andAffordance(afford(methodOn(controllerClass).partiallyUpdateEmployee(null, id))); 

Here, you are creating a self link with Employee details and then associating the updateEmployee and partiallyUpdateEmployee methods to. The GET operation is now connected to the PUT and PATCH operation that can be performed on the Employee.

Spring HATEOAS allows you to define links, their relations, and then associate all possible operations the links can have using affordances. All these are done using a format-agnostic way, which allows the client to choose the format type. Alternatively, you can configure Spring HATEOAS to use a specific format using an annotation, for example:

@Configuration
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL_FORMS)
public class HypermediaConfiguration {

}

Source code for a sample application that makes use of the Spring HATEOAS framework is published here.

Spring HATEOAS Reference Documentation

APIs in the wild

Leave a Reply

Your email address will not be published. Required fields are marked *