Pagination in Rest APIs

Within the scope of pagination, satisfying the HATEOAS constraint of REST means enabling the client of the API to discover the next and previous pages based on the current page in the navigation. For this purpose, we’re going to use the Link HTTP header, coupled with the officialnext“, “prev“, “first” and “last” link relation types.

In REST, Discoverability is a cross-cutting concern, applicable not only to specific operations but to types of operations. For example, each time a Resource is created, the URI of that Resource should be discoverable by the client. Since this requirement is relevant for the creation of ANY Resource, it should be dealt with separately and decoupled from the main Controller flow.

With Spring, this decoupling is done with Events, as was thoroughly discussed in the previous article focusing on Discoverability of a REST Service. In the case of pagination, the event – PaginatedResultsRetrievedEvent – is fired in the controller layer, and discoverability is implemented with a custom listener for this event:

@RequestMapping( value = "admin/foo",params = { "page", "size" }, method = GET )
@ResponseBody
public List< Foo > findPaginated(
 @RequestParam( "page" ) int page, @RequestParam( "size" ) int size,
 UriComponentsBuilder uriBuilder, HttpServletResponse response ){
   Page< Foo > resultPage = service.findPaginated( page, size );
   if( page > resultPage.getTotalPages() ) {
      throw new ResourceNotFoundException();
   }
   eventPublisher.publishEvent( new PaginatedResultsRetrievedEvent< Foo >
    ( Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size ) );
   return resultPage.getContent();
}