HATEOAS Hands-on for Backend and Frontend

HATEOAS Hands-on for Backend and Frontend

RESTful API without HATEOAS is not a RESTful API by definition. Majority of developers refrain from using HATEOAS because it comes with extra complexity, its value is questionable and it’s not really popular in general.

Let’s explore HATEOAS hands-on and see if those concerns hold true. You will learn how to implement HATEOAS on the server side and on the client side using libraries and get access to working code on github (see comment section down below 👇).

Introduction

While the RESTfulness of an API falls on a spectrum, incorporating HATEOAS brings it closer to the ideal. By adopting HATEOAS principles, you can achieve better coordination, simplify development, and enhance the overall collaborative experience.

If you want to have:

  • a robust API by making your clients harder to break
  • self-documenting endpoints that improve communication
  • a standard convention to leverage rich tooling and libraries

Read further and see what I propose to solve the HATEOAS complexity problem.

HATEOAS in Backend

In our example we will use Kotlin and Spring, because I think this is a pretty popular and easy to use setup.

I would suggest you start with designing the API first. For our example we will use OpenAPI 3.0 specification.

No alt text provided for this image
A plan for the Borrow API


We’re going to create a Borrow API to manage things that you lend, so that you will never lose a thing! We’re going to have a Borrowee (because it sounds nice) and an Item. We could have many endpoints to cover many use cases like so:

No alt text provided for this image
The endpoints


But for sake of simplicity we will use only a few, just enough to explain the issue.

You can find the full OAS 3.0 specs in the repository (look in the comment section down below) in resources/borrow.yaml.

OpenAPI specs is the place where you already need to think about HATEOAS. A good idea is to sketch first what links you want to attach where. And don’t forget to leverage JSON Schema i.e. define links in components, not in paths.

OpenAPI

The Borrow API has only two objects (Item, Borrowee) and we could define them like so:

No alt text provided for this image
Example of JSON Schema in YAML🤯

You can see that there is the property “links” which defines two other properties. The “self” and the “borrowee” for Item and “self” and “items” for Borrowee. All of those refer a component from the JSON Schema ($ref: …):

No alt text provided for this image
OAS definition for links


Let’s decode this part. A link is made of 3 parts:

  • Name
  • Operation id
  • Parameters

Take the first one as an example. “borrowee-from-item” is the name of the link. It refers the operation with the id “get-a-borrowee”. This operation id is a concrete path from the specification. In our case it’s this:

No alt text provided for this image
Path definition in OAS

Last but not least, the list of parameters that are used to build the URI e.g. when you have path parameters in your endpoint. Our URI is “/borrowee/{name}”. So the link has a “name” parameter defined. Its value comes from the body of the response. If the response looks like so:

{
	“Name”: “blue pen”,
	“borrowee”: “john”
}        

You can address this property using this syntax: “$response.body#/borrowee”.

This may sound confusing by now. But it’s pretty simple if you approach this in 4 steps:

  1. Define your components in schema
  2. Define your paths and which components they return
  3. Define self links for every component
  4. Define which components should be linked in other components

Now that you have your OpenAPI specs, you have two options. Generate code from it (e.g. models or even interfaces for your controllers) or write your code based on the specifications. This is an article about HATEOAS and not OpenAPI code generation, so let’s just write some code.

Kotlin

We will need two models:

No alt text provided for this image
Definition of data model for our backend

Those will extend the org.springframework.hateoas.RepresentationModel. To use it, you can include this starter in your build.gradle:

implementation("org.springframework.boot:spring-boot-starter-hateoas")        

Now create two controllers. ItemController and BorroweeController. Let’s first add an endpoint returning all items.

No alt text provided for this image
Code, code everywhere

We use RequestParams for page and size. This is used for pagination. In the bottom of the function you can see how we leverage HATEOAS to provide clients with automated pagination:

No alt text provided for this image
A funky pagination using HATEOAS

The CustomCollectionModel is a wrapper around the response. This has two important tasks:

  • Allow for adding extra fields to the model (this is used to add links)
  • Allow us to define the response as we wish. In our case we want to have something like:

{
	“data”: []
	“_links”: {}
}        

Without this wrapper we would not be able to add _links, and without our custom wrapper instead of “data” we would see the “_embedded” property.

The first few lines of code that define the “items” variable is just a database replacement. But it does show HATEOAS in action:

No alt text provided for this image
Adding links to any data model

Because our model extends the RepresentationModel, we can add extra properties i.e. links. Those are generated from the controller and allow us to define the “rel” name. The code from above would generate something similar to:

{
  “name”: “Blue Pen,
  “borrowee”: “John,
  “_links”: {
    “self”: “/item/Blue Pen”,
    “borrowee”: “/borrowee/John”
  }
}        

We will do the same for BorroweeController. But to allow clients to discover the API entirely, we need a main hub with all the endpoints that client can access. Let’s create a HATEOASController:

No alt text provided for this image
HATEOAS controller allows to list all useful links

Great! If you check out the code, you can simply run the app and call those endpoints from the browser or your favourite rest client like Postman or Insomnia.

HATEOAS on Client Side

For the client we will write a simple React app that uses Axiom to read from our API.

Simply create a new React app and add your component.

No alt text provided for this image
A not very sofisticated React component

The interesting part is inside the “loader()” function:

No alt text provided for this image
Accessing the whole API with only base URL defined

As you can see, it only requires the base URL i.e. “localhost:8080”. Every other endpoint is discovered automatically. You only need to call it once to see which resources you want to get.

The result is this:

No alt text provided for this image
Production grade UX/UI

We got all items and borrowees, without even knowing what endpoints we use!

Conclusion

As you can see, HATEOAS is not a scary monster from under the bed. With proper tooling it’s a breeze to configure and use. 

What are your thoughts on HATEOAS? Please let me know and if you think someone could benefit from it, I will be grateful if you share this article.

To view or add a comment, sign in

Insights from the community

Others also viewed

Explore topics