Richardson Maturity Model and HATEOAS

Cahit Barkin Ozer
4 min readApr 3, 2022

Learn Richardson Maturity Model, HATEOAS, and the implementation of HATEOAS in Spring Boot.

Richardson Maturity Level

A model (developed by Leonard Richardson) that breaks down the principal elements of a REST API design approach into three steps. These introduce resources, HTTP verbs, and hypermedia controls.

Richardson Maturity Model Levels for REST APIs

Level 0

For remote interactions, HTTP is used as a transport system.
HTTP is typically used as a tunneling technique for your remote interaction mechanism, which is based on Remote Procedure Invocation.
Level 0 is simply using only Post requests to a single endpoint for all operations.

Richardson Maturity Level 0

Level 1 — Resources

Rather than making all our requests to a singular service endpoint, we start talking to individual resources. Divide and conquer is used to address the issue of dealing with complexity by breaking down a large service endpoint into multiple resources. Level 1 is simply using only Post requests to different post endpoints for all operations.

Richardson Maturity Level 1 — Resources

Level 2 — HTTP Verbs

Using HTTP verbs as nearly as possible to how they are used in HTTP itself. Introduces a standard set of verbs to ensure that identical circumstances are handled in the same way, avoiding unnecessary variety. Level 2 is simply using all sorts of rest requests to their request type endpoints.

Richardson Maturity Level 2 — HTTP Verbs

Level 3 — Hypermedia Controls

HATEOAS (Hypermedia As The Engine Of Application State) is introduced on the last level. HATEOAS addresses the question of how to get from a list of open slots to know what to do to book an appointment. Introduces discoverability, allowing a protocol to become more self-documenting. Level 3 is using all sorts of rest requests to their request-type endpoints and also returning other endpoint’s links (HATEOAS).

Richardson Maturity Level 2 — Hypermedia Controls

HATEOAS

HATEOAS is an acronym that stands for Hypermedia as the Engine of Application State. The final level (3. level) requires the use of HATEOAS.
With HATEOAS, clients can use REST APIs with minimal documentation.
A good REST API (has HATEOAS) often sends the list/links of other resources related to this resource, the action to be taken, and the information that can be obtained.
Example: A request goes to accounts API.

GET /accounts/12345 HTTP/1.1
Host: bank.example.com
Accept: application/vnd.acme.account+json
...

The response to the request is the following.

HTTP/1.1 200 OK
Content-Type: application/vnd.acme.account+json
Content-Length: ...
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": 100.00
},
"links": {
"deposit": "/accounts/12345/deposit",
"withdraw": "/accounts/12345/withdraw",
"transfer": "/accounts/12345/transfer",
"close": "/accounts/12345/close"
}

}
}

As you can see, as well as data, some links that are related to that item return.
Rest API means, “you can do these operations” by sending these links.

After doing an operation that caused the account balance to be negative.
Rest API returns only deposit links, not others. This helps the user of the API to understand the API better.
As you can see there is a sort of programming happening here as well.

HTTP/1.1 200 OK
Content-Type: application/vnd.acme.account+json
Content-Length: …
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": -25.00
},
"links": {
"deposit": "/accounts/12345/deposit"
}

}
}

To implement HATEOAS in Your Spring Boot Controller

WebMvcLinkBuilder is used for the implementation. Links that are coming from the WebMvcLinkBuilder are added with EntityModel. The linked entity model is filled with MappingJacksonValue. Returns mappedJacksonValue as ResponseEntity.

@PostMapping
public ResponseEntity<RestResponse<MappingJacksonValue>>> save(@RequestBody CusCustomerSaveRequestDto cusCustomerSaveRequestDto){

CusCustomerDto cusCustomerDto = cusCustomerService.save(cusCustomerSaveRequestDto);

WebMvcLinkBuilder link = WebMvcLinkBuilder.linkTo(
WebMvcLinkBuilder.methodOn(this.getClass())
.findById(cusCustomerDto.getId()) );
//An EntityModel wraps a domain object and adds links to it. EntityModel entityModel = EntityModel.of(cusCustomerDto);

//Explanation of the link.
entityModel.add(link.withRel("find-by-id"));
//A simple holder for the POJO to serialize with additional serialization instructions to be passed in to the converter. MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(entityModel);


return ResponseEntity.ok(RestResponse.of(mappingJacksonValue));

}

Response after the HATEOAS:

HTTP/1.1 200 OK
Content-Type: application/vnd.acme.account+json
Content-Length: …
{
"data":{
"value": {
"id": 52,
"name": "Yusuf",
"surname": "Memiş",
"identityNo": 12345678901,
"links": [
{
"rel":"find by id",
"href": "http://localhost:8080/api/v1/customer/52"
}

]
},
"responseDate":"2022-02-27T06:26:48,136+00:00",
"messages":null,
"success":true
}
}

Thank you for reading. Please do not forget to clap if you think it was helpful.

References

https://martinfowler.com/articles/richardsonMaturityModel.html

--

--

Cahit Barkin Ozer

Daha fazla şey öğrenmek ve daha iyi olmak isteyen bir yazılım mühendisi.