CodingNic

REST API Design

Filtering, Sorting, and Search

REST API Design 12 min read

Filtering, Sorting, and Search

Objectives

By the end of this lesson, you should be able to:

  • Filter a collection endpoint by an exact field value
  • Sort a collection by any field, ascending or descending
  • Add a simple text search across a field, and combine it with filtering and sorting

💡 Why this matters: A real client rarely wants an entire collection, it wants products in one category, sorted cheapest first, or every result matching a search term. Query parameters (Module 5) are the standard way a REST API exposes this.

⚠️ A note on verification: every snippet and every response shown below was actually run and tested with real HTTP requests.

Filtering by an Exact Value

javascript
app.get('/products', (req, res) => {
  let results = [...products];

  if (req.query.category) {
    results = results.filter(p => p.category === req.query.category);
  }

  res.json(results);
});
bash
curl "http://localhost:4505/products?category=accessories"
text
[{"id":1,"name":"Keyboard","category":"accessories","price":45},{"id":3,"name":"Mechanical Keyboard","category":"accessories","price":89},{"id":4,"name":"Webcam","category":"accessories","price":60}]

[...products] (Module 2’s spread) copies the array first, so filtering never mutates the original data, req.query.category, only applied if it’s present, means the endpoint still returns everything when no filter is requested, filtering stays entirely optional.

javascript
if (req.query.q) {
  const term = req.query.q.toLowerCase();
  results = results.filter(p => p.name.toLowerCase().includes(term));
}
bash
curl "http://localhost:4505/products?q=key"
text
[{"id":1,"name":"Keyboard","category":"accessories","price":45},{"id":3,"name":"Mechanical Keyboard","category":"accessories","price":89}]

q (a common, short convention for a search query parameter) is lowercased on both sides (.toLowerCase(), Module 2’s string methods) before comparing with .includes(), making the search case-insensitive, "key" correctly matches both "Keyboard" and "Mechanical Keyboard".

Sorting

javascript
if (req.query.sort) {
  const desc = req.query.sort.startsWith('-');
  const field = desc ? req.query.sort.slice(1) : req.query.sort;
  results.sort((a, b) => {
    if (a[field] < b[field]) return desc ? 1 : -1;
    if (a[field] > b[field]) return desc ? -1 : 1;
    return 0;
  });
}
bash
curl "http://localhost:4505/products?sort=price"
text
[{"id":1,"name":"Keyboard","price":45,...},{"id":4,"name":"Webcam","price":60,...},{"id":3,"name":"Mechanical Keyboard","price":89,...},{"id":2,"name":"Monitor","price":210,...}]
bash
curl "http://localhost:4505/products?sort=-price"
text
[{"id":2,"name":"Monitor","price":210,...},{"id":3,"name":"Mechanical Keyboard","price":89,...},{"id":4,"name":"Webcam","price":60,...},{"id":1,"name":"Keyboard","price":45,...}]

A leading - on the sort value is a common convention for descending order, sort=price sorts ascending, sort=-price sorts descending, this reads naturally (-price as “negative price,” conceptually “highest first”) and avoids needing a second query parameter just for direction.

Combining Filtering, Search, and Sorting

bash
curl "http://localhost:4505/products?category=accessories&sort=-price"
text
[{"id":3,"name":"Mechanical Keyboard","price":89,...},{"id":4,"name":"Webcam","price":60,...},{"id":1,"name":"Keyboard","price":45,...}]

Because each feature checks its own req.query field independently, and reassigns the same results variable, they compose naturally, filtering by category, then sorting the filtered results, exactly as shown, no special coordination code needed between them.

Try It

  1. Add filtering by an exact field (like category above) to a collection endpoint of your own, and test it with and without the filter applied.
  2. Add a q search parameter searching across a text field, case-insensitively, and confirm it matches partial, differently-cased input correctly.
  3. Add sort support, including the -field descending convention, and confirm both directions produce correctly ordered results.
  4. Combine all three (filter, search, sort) in a single request, and confirm the result is correct for that combination.

Recap

  • Filtering checks a query parameter against an exact field value, applied only when the parameter is present, keeping it optional.
  • A q parameter, lowercased and matched with .includes(), provides simple, case-insensitive text search.
  • sort=field sorts ascending, sort=-field (a leading -) sorts descending, a common, self-documenting convention.

Next lesson: REST best practices, tying every convention in this module together.