javaspringspring-bootjpa

Presenting a link to request to the next page in Spring controller


I have this controller:

// Gets a list of the latest listings, think like Ebay or Craigslist
@ResponseBody
@GetMapping("/listings")
public ResponseEntity<List<Listing>> getListings(@RequestParam(defaultValue = "0", name="pageNumber") String pageNumber,
                                                      @RequestParam(defaultValue = "200") String pageSize) {
    PageRequest page;
    try {
        page = PageRequest.of(Integer.parseInt(pageNumber), Integer.parseInt(pageSize),
                Sort.by(Sort.Direction.DESC, "id"));
    } catch (NumberFormatException _) {
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "One or more parameters were not accepted.");
    }

    List<Listing> listings = listingsService.getListings(page);

    return new ResponseEntity<>(Listings, HttpStatus.OK);
}

My goal here is to embed a link to request the next page of data within the body of the response, something like this:

{
  "listings": { ... },
  "meta": {
    "paging": {
      "previous": "https://myplace/?pageNumber=n-1",
      "next": "https://myplace/?pageNumber=n+1"
    }
  },
}

But I'm not sure if I should use a feature of ResponseEntity, create a new object which extends a list of listings with these details, or I'm going about this wrong and should do something entirely differently. I need some advice on this.


Solution

  • I recommend using Pageable and Page from spring rather than managing this yourself. Your controller would return a Page<Listing> (or a ResponseEntity<Page<Listing>> if you have other things to inject into the ResponseEntity).

    Without knowing how you're fetching your data, here's some updates to how this would work

    @ResponseBody
    @GetMapping("/listings")
    public Page<Listing> getListings(Pageable pageable) {
        // fetch data.  Repositories will accept a "Pageable", so something like this
        Page<Listing> pageOfListings = listingRepository.findAll(pageable);
        
        // if you don't have a repository, you could also build your own Page
        if(noRepositoryExists) {
            pageOfListings = new PageImpl(listingsFetchedFromSomewhereElse, pageable, (Long) totalListingsAvailable);
        }
    
        return pageOfListings;
    }
    

    If that's not a viable option you can create a wrapper for your List<Listing> and return that instead

    public class ListingPage {
      private List<Listing> listings;
      private PageInfo meta;
    }