Implementing API Pagination

1. Implementing Offset-Based Pagination

Example: Offset query

@GetMapping("/orders")
public PageResponse<OrderResponse> list(
    @RequestParam(defaultValue="0") int page,
    @RequestParam(defaultValue="20") int size) {
    var pg = PageRequest.of(page, size, Sort.by("placedAt").descending());
    return mapper.toResponse(orderRepo.findAll(pg));
}
Warning: Offset pagination becomes O(N) at the DB; avoid for large datasets — use cursor.

2. Implementing Cursor-Based Pagination

Example: Keyset cursor

-- cursor encodes (placed_at, id) of last item
SELECT * FROM orders
WHERE (placed_at, id) < (?, ?)
ORDER BY placed_at DESC, id DESC
LIMIT 21;  -- 1 extra to detect hasNext

3. Designing Page Response Format

FieldPurpose
itemsPage contents
page, sizeOffset metadata
totalElements, totalPagesIf known
nextCursor, prevCursorCursor metadata
hasNext, hasPrevConvenience flags

4. Implementing Total Count Calculation

ApproachTrade-off
Exact COUNT(*)Slow on big tables
Estimatedpg_class.reltuples (PG)
Skip totalCursor pagination
Async totalCompute separately, cache

5. Handling Empty Results

Example: Empty page

{ "items": [], "page": 0, "size": 20, "totalElements": 0,
  "totalPages": 0, "hasNext": false, "hasPrev": false }

6. Designing Default Page Sizes

SettingRecommendation
Default size20
Max size100 (cap to prevent abuse)
ValidateReject > max with 400

7. Implementing Sorting with Pagination

AspectDetail
Format?sort=field,direction
Multiple?sort=status,asc&sort=placedAt,desc
Allow-listWhitelist sortable fields
Stable sortAppend PK as tie-breaker
"_links": {
  "self":  { "href": "/orders?page=2&size=20" },
  "first": { "href": "/orders?page=0&size=20" },
  "prev":  { "href": "/orders?page=1&size=20" },
  "next":  { "href": "/orders?page=3&size=20" },
  "last":  { "href": "/orders?page=99&size=20" }
}

9. Handling Large Datasets

StrategyDetail
Cursor paginationO(1) per page
StreamingNDJSON / chunked transfer
Async exportGenerate file, notify when done
Read replicaOffload analytics queries

10. Implementing Search with Pagination

ConcernDetail
Index sortMatch search engine sort order
Result freshnessDocument new results between pages
Scroll APIElasticsearch search_after

11. Implementing Pagination Metadata

HeaderPurpose
X-Total-CountTotal items
LinkRFC 5988 next/prev/first/last
X-Page, X-Page-SizeCurrent page info

12. Implementing Consistent Pagination

IssueMitigation
Inserts shift offsetUse cursor, not offset
Sort field collisionsTie-break on PK
Deleted itemsSnapshot or filter at query time