Real-world APIs need more than flat CRUD routes, they need nested resources, filtering, and pagination. This lesson covers those patterns on top of what you've already built.
Nested Resources
When one resource belongs to another, comments belonging to a post, items belonging to an order, nested routes express that relationship directly in the URL: /posts/:postId/comments. Express's express.Router({ mergeParams: true }) lets a nested router still access the parent's route parameters.
Filtering, sorting, and pagination, on the other hand, are usually expressed through query parameters rather than the path itself, since they modify how a collection is retrieved without changing which resource is being addressed.
{ mergeParams: true } is what lets commentsRouter see req.params.postId, which was captured by the parent router's :postId segment.
Query Parameters for Filtering
GET /products?category=electronics
GET /products?sort=price&order=desc
GET /products?page=2&limit=20
Filtering: ?category=electronics narrows a collection without changing the resource itself.
Sorting: ?sort=price&order=desc controls result ordering.
Pagination: ?page=2&limit=20 limits how many results are returned per request.
All of these live in req.query, parsed automatically by Express from the query string.
API Routing Patterns Cheatsheet
Common patterns beyond basic single-resource CRUD.
Pattern
Example URL
Nested resource
/posts/:postId/comments
Filtering
/products?category=electronics
Sorting
/products?sort=price&order=asc
Pagination
/products?page=2&limit=20
Search
/products?q=keyboard
Field selection
/products?fields=id,name
Implementing Pagination
Returning an entire collection at once doesn't scale as data grows. Pagination lets clients request a manageable slice at a time, using page/limit (offset-based) or a cursor-based approach for very large or frequently-changing datasets.
Including total in the response lets clients calculate how many pages exist without a separate request.
Combining Multiple Filters Safely
As more query parameters are supported, validate and apply them incrementally rather than trusting arbitrary input directly, especially before passing filter values into a database query.
Whitelist which query parameters your endpoint actually supports.
Validate types and ranges (e.g. limit shouldn't be negative or absurdly large).
Never interpolate raw query parameters directly into a SQL string, see the Request Validation and Databases lessons.
Common Mistakes
Returning an entire large collection with no pagination support at all.
Forgetting { mergeParams: true } on a nested router, losing access to a parent route's parameters.
Trusting query parameters blindly without validating their type or range before using them.
Mixing filtering logic directly into route handlers instead of a reusable query-building helper.
Key Takeaways
Nested routes express "belongs to" relationships directly in the URL path.
Filtering, sorting, and pagination are expressed through query parameters, not the path.
Always validate and whitelist query parameters before using them to build data queries.
Pro Tip
Always return pagination metadata (page, limit, total) alongside paginated results, even if your first client doesn't use it yet. Adding it retroactively is a breaking change; including it from the start costs almost nothing.
You now know advanced routing patterns for real APIs. Next, learn how to validate incoming request data before it reaches your business logic.