APIs · Lesson 10
Pagination and Filtering
Serving Large Collections
Returning every item from a growing collection creates slow responses and unnecessary memory use. Pagination limits each response to a page, while filtering narrows the result set before it is returned. Together they make collection endpoints predictable for clients and databases.
Modeling a Page
A page response should tell clients what they received and how to request more. Cursor-based approaches are often more stable than offsets when records change frequently.
import java.util.List;
public record Page<T>(List<T> items, String nextCursor, boolean hasNextPage) {
public static void main(String[] arguments) {
Page<String> firstPage = new Page<>(List.of("Servlets", "JDBC"), "cursor-2", true);
System.out.println(firstPage.items() + "; next: " + firstPage.nextCursor());
}
}
Pagination Comparison
| Style | Request example | Strength | Trade-off |
|---|---|---|---|
| Offset | ?page=3&size=20 | Easy to understand | Shifts under inserts |
| Cursor | ?after=cursor-2 | Stable traversal | Less random access |
| Time-based | ?before=timestamp | Useful for feeds | Needs ordered timestamps |
Common Mistake and Practices
Common Mistake: Accepting an unlimited page size from a client. A single request can then consume excessive database and application resources.
- Cap page size on the server.
- Define stable sort order.
- Validate filters and reject unknown fields.
- Return pagination metadata.
- Add indexes for common filters and ordering.
Real-World Use Case
The lesson catalog returns 20 lessons at a time and supports filtering by module. A cursor lets a learner continue browsing consistently even when new lessons are published.
Quiz Check