HATEOAS paging with Spring MVC and Spring Data JPA


In a previous post, I exposed the principles of HATEOAS and illustrated these principles with an implementation based on Spring MVC and Spring HATEOAS. In this post, I’ll go further with the implementation of a paged REST web services that follows the guidelines of HATEOAS. This implementation is based again on Spring MVC and Spring HATEOAS, and uses Spring Data JPA‘s built-in paging features for the database backend.

Paged REST controller, no HATEOAS

The first version of our controller doesn’t implement HATEOAS guidelines, as the representation of a page contains the content itself (contact records) and information about the page itself (number, size, etc), but no link to navigate to the previous or to the next page.

Here is the first version of our controller:

Some explanations:

the client provides the number of the requested page and the size with HTTP parameters. The end of the URL would look like /contacts/pages?page=1&size=5.

the controller uses Spring Data JPA paging support. It builds a PageRequest object from the HTTP parameters, chooses to sort by ID, calls the Spring Data JPA repository, and gets a Page.

The controller returns the Page, Spring MVC takes care of generating some JSON from the Page.

Here is what the representation looks like in this version (content first and then page information):

In the previous post, we worked on making the records HATEOAS: a contact record was a summary of the contact resource and contained a link to GET to the detail of the contact. We could apply the exact same techniques in this post, but we’ll leave the records alone and focus on the page itself. We want a page to expose links to the previous/next/first/last pages.

We will make these links available by wrapping a page in a link-aware custom class.

The link-aware page wrapper

The page wrapper has the following goals:

  • exposing the page – that’s why it implements Page and delegates all the methods to the underlying page (the one returned by the repository)
  • building and exposing the links – it builds the links in its constructor and exposes them thanks to a base class that Spring Data provides.

Here is the wrapper:


I left only the parts that matter. There are different links but they’re all built in the same way. I use Spring MVC’s ServletUriComponentsBuilder to build the URL from the current request, with the appropriate HTTP parameters for the paging, and then create a Spring HATEOAS Link from the URL. The ServletUriComponentsBuilder is handy when it comes to build URL, as it handles path variables, expanding of the path template with values, and encoding.

New version of the controller

The controller doesn’t change much, it just needs to build a PageResource from the page and return it:

Here is how the JSON representation looks like now:

Notice the id and the links fields. They come from the ResourceSupport our PageResource class extends.

A client of our REST web service is now able to navigate through the pages of our list of contacts. This client could be your favorite AJAX library, like JQuery, that would hit the web service and nicely formats the data in an HTML interface.


This post illustrated how to make a REST web service easier to use from the client’s point of view: result pages contain links to navigate through the dataset. The implementation has been made straightforward thanks to the use of Spring Data JPA, Spring MVC, and Spring HATEOAS.

Source code

Partagez cet article.

A propos de l'auteur

3 commentaires

  1. Hi Arnaud,

    Very nice article, I could implement it easily, thanks for this good explanation. I reckon there is now some alternative offered by the Spring framework though, that makes the hand coding of the PageResource class no longer required. But still, very good if only for educational purposes. Thanks !

    Kind Regards,

    Stephane Eybert

  2. Hi,
    Thank for this good example!
    Based on this, how would manage to be sure each T has its own Hateoas links ?
    Their should be at least the « self » one for the client to know where to go when it has choosen the element he wanted…

Ajouter un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.