Search sort filter in Node.js Express API

How to Implement Search, Sort, and Filter in Your Node.js + Express REST API

Delivering the right data at the right time is one of the most important responsibilities of a well-designed API. Users expect fast, accurate, and flexible querying — and that means your backend needs solid search, sort, and filter capabilities.

In this post, I’ll show you how to implement all three in a clean and scalable way using Node.js, Express, and Prisma ORM.


Why Search, Sort, and Filter Matter

A typical client request to your API includes query parameters such as:

  • search → find records containing certain text
  • completed → filter by boolean-like values
  • orderBy → return data sorted by specific fields

Your server is responsible for parsing these parameters and translating them into where and orderBy conditions that your ORM can use to query the database.

In this tutorial, we’ll use Prisma ORM, but the same principles apply regardless of your data layer.


Step 1: Updating the Repository Interfaces

Before writing any logic, we start by updating the repository interface to define what our API can accept.
We add support for:

  • search?: string
  • completed?: boolean
  • orderBy?: { createdAt?: "asc" | "desc"; dueDate?: "asc" | "desc" }

Why limit fields?

When your app grows, indexing becomes critical. Allowing users to search or sort on too many fields leads to index bloat and slower write operations.
That’s why in this example we limit search and sorting to a small, intentional set of fields.

🚀 Complete JavaScript Guide (Beginner + Advanced)

🚀 NodeJS – The Complete Guide (MVC, REST APIs, GraphQL, Deno)


Step 2: Implementing Search

For this project, we only search by task name.

Could we also search descriptions?
Yes — but if your project has a large dataset, description search would require:

  • A full-text index, and
  • Different Prisma syntax for full-text queries

If you need more advanced search capabilities, you should look into dedicated search engines like Algolia.


Step 3: Implementing Filter Logic

Filtering by completion is more complex than it looks.

Instead of a simple boolean field (isCompleted: true/false), this system uses a completedOn date. That means:

  • If the task is completed → completedOn contains a date
  • If not → completedOn is null

So filtering works like this:

  • completed=true → return tasks where completedOn is not null
  • completed=false → return tasks where completedOn is null
  • filter omitted → return all tasks

This kind of nuance appears frequently in real-world APIs, so it’s important to handle it correctly.


Step 4: Implementing Sorting

Sorting is passed as a single query parameter in the format:

createdAt-desc

The API splits this into:

  • the field (createdAt or dueDate)
  • the direction (asc or desc)

We validate both so users can’t sort by arbitrary fields.

The final result maps directly to Prisma’s orderBy object structure.


Step 5: Parsing Query Parameters

To keep your controllers clean and organized, it’s best to introduce a helper function:

parseTaskQueryParameters(req)

This function:

  1. Reads raw query values
  2. Validates them
  3. Converts them into the structured format your repository layer expects

Doing this in a centralized utility:

  • avoids duplicated logic
  • makes future changes easy
  • keeps your controllers readable

Step 6: Updating the Controller

With the parsing logic in place, the controller becomes extremely simple:

  1. Extract query parameters
  2. Pass them to the repository
  3. Return the results

Clean architecture at work.


Step 7: Testing Your API

Example test queries:

  • /tasks?search=task
  • /tasks?search=task&completed=false
  • /tasks?search=task&completed=false&orderBy=createdAt-desc

The results:

  • match the search term
  • include only completed or incomplete tasks
  • are sorted by the field and direction you specify

Everything works exactly as expected.

Share this article

Similar Posts