user-icon Constantin Weißer
07. June 2017
timer-icon 6 min

Automatic Page Links with HATEOAS in Spring Boot

Overview of topics in this post

  • REST API pagination
  • HATEOAS links, specifically for pagination as an example
  • Spring Boot Support for HATEOAS
  • Aspect Oriented Programming (AOP) as a tool to reuse crosscutting code(optional enhancement)

In short: we will develop a quick solution to generate reliable page links to “browse” pages of REST resources where the Spring HATEOAS support is still a bit bumpy.

Introduction

If you’re writing a REST service that provides lists of things (what REST service doesn’t?), you have probably thought about pagination of the result lists. If you haven’t, you should. With pagination you provide chunks of results to the client rather than all results at the same time. This often goes very well with the way clients process the results. For example, when the client presents the entries to the user, it will often also show only a bunch of items at a time. Infinite scrolling pages also go well with the concept of pagination, as you can load one “page” at a time and add them to the infinite list. By delivering chunks of objects to the client, which might be exactly what the client needs, you also make the load on the backing service manageable.

In the project I’m working on, we combine pagination of results with HATEOAS. HATEOAS adds hyperlinks to REST resources (the “encoding” of those links is sometimes called HAL, a draft for the standard can be found at https://tools.ietf.org/html/draft-kelly-json-hal-08). You basically specify actions that can be performed on the resource at hand and provide the URL to perform the actions on the back-end service. This can make your service more robust to changes in the URL patterns, as HAL-clients just follow the links and need not compose request URLs themselves. It also makes the service somewhat “explorable” by developers.

The links might also come at a cost for the back-end service. If the goal is to communicate the client’s possible actions with the presence (or absence) of links, the service must sometimes implement (expensive) business logic just to assemble a resource. One should balance the benefits against the cost.

Spring Boot Support for Pagination

In Spring Boot, both concepts, pagination and links, are supported out of the box. For example, by adding a Pageable parameter to your request mapping method, Spring will parse the query parameters page=, size= and sort= and make them available to you through that Pageable. Conveniently, you can pass down the Pageable instance to your repository. Spring Data will manage the pagination and sorting of the result automatically. That lowers the effort to provide pagination in a REST API substiantially.


The code example shows a basic request mapping, also taking a Pageable as parameter. It can then be passed on to the JpaRepository, like so:


The returned value is a page containing a subset of the complete result set which respects the constraints given through the pageable such as maximum size and sorting.

Spring Boot Support for HATEOAS

So much for pagination. But what about the hypermedia links? Even though there’s so much “HATE” in the name, you certainly do not want to feel the hate in building the links manually. Thankfully, there is Spring support also for this task. It generally works quite well. You can build links referring to methods on RESTControllers like so:


The Greeting resource class must extend ResourceSupport so you can add links to it. (The full example is on https://spring.io/guides/gs/rest-hateoas/)

This approach works for many scenarios, however, I noticed a shortcoming. Say, we have a GET request:


The “customerListResourceAssembler” might want to add links to the CustomerListResource referring to the next or previous page, if such a page is available. But if we do


we won’t get what we want. Spring will create a link like this:


So it effectively drops all the parameters that were sent with the initial request plus it ignores query parameters that we specify during the link generation. The link will work, doubtlessly, but it will not return the page with the content that we actually want. So I tried to figure out a way to fix this, which I can easily reuse throughout the project.

The solution consists of two things, firstly the code that actually adds the links. Secondly, I wrapped the logic in a simple aspect (as in aspect oriented programming, which is very easy to integrate with Spring Boot). That way, I can reuse it by simply adding a custom annotation to my factory/assembler methods.

Generating the right URLs

We will build the correct URLs using the current request URL as a template. Obviously, this comes with the restriction that we can only build links for the currently requested resource this way. On the other hand, this is the only request we have the remaining query parameters available for. From the request context we will get the parameter map and replace only the page parameter:


Where the replacePageParams() method just does what its name suggests:

Wrapping it up in an annotation

The code snippet above can be integrated easily by creating some helper functions which can be called from a resource factory for example. Alternatively, one could use a more descriptive way and control the links with an annotation. For that, we define a new annotation like so:


Instead of creating helper methods that are called explicitly, we can wrap the logic in an aspect, that affects assembling methods that are annotated. In Spring, that’s a rather simple task: We must make sure that the configuration option spring.aop.auto is set to true.

Then we can create an aspect:


and within we can create an “advice” that intercepts calls to all methods with matching signature and our PageLinks annotation:


The @annotation() part limits the advice to methods with this annotation. The execution() part limits it to methods with return type derived from ResourceSupport (note the ) and any parameter types and numbers. The args() part binds the first argument of the annotated method to the parameter page of the advice method so we can access it easily. Within the advice method we simply implement the logic described above by wrapping the call to the assembler method with our page links logic. The resulting combination can be investigated here. In the implementation of this wrapper it is important to do


The proceed() method on the ProceedingJoinPoint will perform the call to the method whose call we intercepted with this aspect. So we get its result back and we can now apply our URL magic before returning it to the original caller.

By adding the annotation to a assembler method, we can now use the page links logic without writing any imperative code. For example:


Where the return type CustomerListResource must extend ResourceSupport!

That’s about it. The aspect will “magically” add links to the resource depending on whether the passed Page object has next and/or previous pages. The functionality is nicely tucked in an advice so you can reuse it with a descriptive annotation.

Summary

  • We talked about breaking down huge result sets into chunks or “pages”
  • We discussed HATEOAS in the specific example of links to next and previous pages
  • We have seen how we can build those links reliably while retaining all other query parameters
  • We have seen a simple example for aspect oriented programming in Spring.

Thank you for reading. Feel free to comment or contact me with questions or feedback.

Comment article

Comments

  1. AhmedJaad

    This is great, I’ve been looking for this for ages, can you provide a link to the full source code

  2. help

    do you have this project github link?