Skip to main content
The Ecommerce API uses Spring Data’s pagination support to efficiently handle large datasets. This guide explains how to use pagination in your requests.

How Pagination Works

Pagination is implemented using Spring Data’s Pageable interface with HATEOAS links for navigation. The /products endpoint demonstrates this functionality.

Products Endpoint Implementation

ProductController.java
@GetMapping("/products")
PagedModel<EntityModel<ProductView>> findAll(Pageable pageable){
    Page<Product> page = productRepository.findAll(pageable);

    Page<ProductView> productViewPage = page.map(
            ProductView::new
    );

    return pagedResourceAssembler
            .toModel(productViewPage);
}

Query Parameters

Control pagination using URL query parameters:
page
integer
default:"0"
The page number to retrieve (zero-indexed)
size
integer
default:"20"
Number of items per page. Maximum value is 50.
sort
string
Sort criteria in the format property,direction (e.g., name,asc or price,desc)

Example Requests

curl http://localhost:8080/products
# Returns first page with 20 items

Configuration

Pagination defaults are configured in application.properties:
application.properties
spring.data.web.pageable.default-page-size=20
spring.data.web.pageable.max-page-size=50
spring.data.web.pageable.default-page-size
integer
default:"20"
Default number of items per page when size parameter is not specified
spring.data.web.pageable.max-page-size
integer
default:"50"
Maximum allowed page size. Requests exceeding this value will be capped at 50.
The maximum page size of 50 prevents excessive data retrieval and ensures consistent API performance.

Response Structure

Paginated responses use Spring HATEOAS’s PagedModel format:
Example Response
{
  "_embedded": {
    "productViewList": [
      {
        "id": 1,
        "name": "Laptop",
        "description": "High-performance laptop",
        "price": 999.99,
        "stockQuantity": 50,
        "_links": {
          "self": {
            "href": "http://localhost:8080/products/1"
          },
          "products": {
            "href": "http://localhost:8080/products"
          }
        }
      },
      {
        "id": 2,
        "name": "Mouse",
        "description": "Wireless mouse",
        "price": 29.99,
        "stockQuantity": 200,
        "_links": {
          "self": {
            "href": "http://localhost:8080/products/2"
          },
          "products": {
            "href": "http://localhost:8080/products"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/products?page=0&size=20"
    },
    "self": {
      "href": "http://localhost:8080/products?page=0&size=20"
    },
    "next": {
      "href": "http://localhost:8080/products?page=1&size=20"
    },
    "last": {
      "href": "http://localhost:8080/products?page=4&size=20"
    }
  },
  "page": {
    "size": 20,
    "totalElements": 100,
    "totalPages": 5,
    "number": 0
  }
}

Response Fields

_embedded.productViewList
array
Array of product objects on the current page
HATEOAS navigation links for pagination:
  • first: First page
  • self: Current page
  • next: Next page (if available)
  • prev: Previous page (if available)
  • last: Last page
page.size
integer
Number of items per page
page.totalElements
integer
Total number of items across all pages
page.totalPages
integer
Total number of pages
page.number
integer
Current page number (zero-indexed)
The API uses Hypermedia as the Engine of Application State (HATEOAS) to provide navigation links:
1

Access First Page

Start with the default endpoint:
curl http://localhost:8080/products
2

Navigate Using Links

Use the next link from the response to get the next page:
curl "http://localhost:8080/products?page=1&size=20"
3

Jump to Last Page

Use the last link to jump directly to the final page:
curl "http://localhost:8080/products?page=4&size=20"
HATEOAS links allow clients to navigate without hardcoding URLs. Always use the provided links for pagination navigation.

Handling Edge Cases

Empty Results

When no products exist, the API returns an empty page:
{
  "_embedded": {
    "productViewList": []
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/products?page=0&size=20"
    }
  },
  "page": {
    "size": 20,
    "totalElements": 0,
    "totalPages": 0,
    "number": 0
  }
}

Page Out of Range

Requesting a page beyond the total pages returns an empty result:
curl "http://localhost:8080/products?page=999"
{
  "_embedded": {
    "productViewList": []
  },
  "page": {
    "size": 20,
    "totalElements": 100,
    "totalPages": 5,
    "number": 999
  }
}
Always check totalPages to avoid requesting pages that don’t exist.

Size Exceeds Maximum

Requesting a size greater than 50 will be capped:
curl "http://localhost:8080/products?size=100"
# Returns 50 items (maximum allowed)

Best Practices

1

Use Appropriate Page Sizes

Balance between performance and user experience:
  • Mobile apps: 10-20 items
  • Web applications: 20-50 items
  • Data exports: Maximum allowed (50)
2

Implement Client-Side Caching

Cache pages to reduce API calls:
const pageCache = new Map();

async function fetchPage(pageNumber) {
  if (pageCache.has(pageNumber)) {
    return pageCache.get(pageNumber);
  }
  
  const response = await fetch(
    `http://localhost:8080/products?page=${pageNumber}`
  );
  const data = await response.json();
  pageCache.set(pageNumber, data);
  return data;
}
3

Handle Navigation Links

Always use HATEOAS links instead of constructing URLs:
async function getNextPage(currentPageData) {
  if (currentPageData._links.next) {
    const response = await fetch(currentPageData._links.next.href);
    return await response.json();
  }
  return null; // No more pages
}
4

Display Total Count

Show users the total number of items:
const totalItems = response.page.totalElements;
console.log(`Showing ${items.length} of ${totalItems} products`);

Sorting Options

Combine pagination with sorting for powerful data retrieval:
Sort ParameterDescriptionExample
sort=name,ascSort by name ascendingA-Z
sort=name,descSort by name descendingZ-A
sort=price,ascSort by price ascendingLowest first
sort=price,descSort by price descendingHighest first
sort=createdAt,descSort by creation dateNewest first
sort=stockQuantity,ascSort by stockLowest stock first

Multiple Sort Fields

curl "http://localhost:8080/products?sort=stockQuantity,asc&sort=price,desc"
This sorts by stock quantity (ascending), then by price (descending) for items with the same stock.

Next Steps

Products API

View detailed product endpoint documentation

Error Handling

Learn how pagination errors are handled

Build docs developers (and LLMs) love