In this lesson, you will learn how to create a Global Search API Middleware that automatically standardizes filtering, pagination, and sorting logic across all your collection endpoints.
The Problem of Repetitive Query Logic
When building a REST API, you often find yourself writing the same code over and over: parsing ?page=1&limit=10, checking for ?sort=createdAt, and translating ?filter[status]=active into database queries. If you handle this manually in every route, your codebase becomes bloated and error-prone.
Centralizing Logic with Middleware
A "Global Search API Middleware" acts as a pre-processing layer that intercepts incoming requests, sanitizes the query parameters, and attaches a standardized queryOptions object to the req object. This allows your route handlers to focus solely on executing the database query without worrying about the messy details of input formatting.
Here is a simplified example of how this middleware transforms a raw request:
const searchMiddleware = (req, res, next) => {
// Extract and standardize query parameters
const { page, limit, sort, filter } = req.query;
req.queryOptions = {
page: parseInt(page) || 1,
limit: parseInt(limit) || 20,
sort: sort || 'createdAt:desc',
filters: filter ? JSON.parse(filter) : {}
};
next();
};
// Usage in a route
app.get('/users', searchMiddleware, async (req, res) => {
// The route handler just uses the pre-formatted data
const users = await db.users.findMany(req.queryOptions);
res.json(users);
});
Why This Matters
By standardizing these inputs, you ensure that every resource—whether it's /users, /products, or /orders—responds to the exact same URL patterns for data navigation. If you ever need to change your default pagination limit or add a new global security filter (e.g., ensuring deleted: false is always applied), you only have to update the logic in one single file. This creates a clean, predictable API surface for your frontend developers while keeping your backend controllers lean and maintainable.
Key Takeaway: Global Search Middleware promotes consistency and code reuse by offloading the parsing of pagination, sorting, and filtering logic from individual route handlers into a centralized, reusable pipeline component.