API Query Parameters to MongoDB
api-query-params is a JavaScript library designed to convert standard API URL query parameters into MongoDB query objects, facilitating advanced filtering, sorting, and projection directly from HTTP requests. Currently at version 6.1.0, the package sees active maintenance with minor versions and patches released regularly to address bug fixes and introduce new features. Key differentiators include its comprehensive support for most MongoDB operators ($in, $regexp, $gt, etc.), nested object querying, and type casting, while remaining agnostic to the specific web framework (e.g., Express, Koa) or MongoDB library (e.g., Mongoose). It offers customization for query keys and options and is noted for its compact, dependency-free ES6 codebase, aiming for simplicity and full test coverage.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use `require()` syntax with `api-query-params` v6.0.1 or newer, which is an ES Module (ESM) library.fixChange your import statement from `const aqp = require('api-query-params');` to `import aqp from 'api-query-params';`. Ensure your Node.js environment is configured for ESM (e.g., `"type": "module"` in `package.json`). -
TypeError: aqp is not a function
cause Incorrectly importing `aqp` as a named import when it is a default export, or attempting to use a CommonJS default export in an ESM context incorrectly.fixEnsure you are using `import aqp from 'api-query-params';` for ESM, or if in a CJS context (pre-v6), `const aqp = require('api-query-params');`. -
TS2305: Module '"api-query-params"' has no exported member 'AqpQuery'.
cause Attempting to import the `AqpQuery` type using a value import statement instead of a type-only import in TypeScript, or incorrect version usage.fixUse `import type { AqpQuery } from 'api-query-params';` to correctly import the type. Also, ensure you are on a version that ships types (>=5.1.0, with improvements in 5.4.0).
Warnings
- breaking Version 6.0.1 of `api-query-params` migrated the entire library to ES Modules (ESM), which breaks existing CommonJS `require()` statements. Applications must migrate to ESM `import` syntax.
- gotcha The `population` field returned by `aqp` is specifically formatted for Mongoose's `populate()` method. It will not work out-of-the-box with other MongoDB drivers or ORMs without custom adaptation.
- gotcha Prior to v6.1.0, query parameters containing file paths with slashes or regex wildcards could be incorrectly split during parsing, leading to malformed or unintended filters.
- gotcha Before v6.1.0, custom casters for object values could erroneously generate a `$not` operator instead of the intended `$ne` (not equal), leading to unexpected query behavior in MongoDB.
- gotcha Versions prior to v5.3.1 had issues correctly parsing multiple query parameters with the same key but different operators (e.g., `field>10&field<20`), leading to incorrect or incomplete query criteria.
Install
-
npm install api-query-params -
yarn add api-query-params -
pnpm add api-query-params
Imports
- aqp
const aqp = require('api-query-params');import aqp from 'api-query-params';
- AqpQuery
import { AqpQuery } from 'api-query-params';import type { AqpQuery } from 'api-query-params'; - aqp (parsed object)
import aqp from 'api-query-params'; // ... later ... const query = aqp(new URLSearchParams(req.query).toString());
import aqp from 'api-query-params'; // ... later ... const query = aqp(req.query);
Quickstart
import express from 'express';
import aqp from 'api-query-params';
import mongoose from 'mongoose';
const app = express();
// Dummy Mongoose Setup (replace with your actual connection and model)
mongoose.connect(process.env.MONGODB_URI ?? 'mongodb://localhost:27017/testdb');
const UserSchema = new mongoose.Schema({
name: String,
email: String,
age: Number,
status: String,
createdAt: Date
});
const User = mongoose.model('User', UserSchema);
app.get('/users', async (req, res, next) => {
try {
const { filter, skip, limit, sort, projection, population } = aqp(req.query);
// Populate with a dummy 'logs' model if needed for example
// In a real app, ensure 'population' paths correspond to actual schemas.
const users = await User.find(filter)
.skip(skip)
.limit(limit)
.sort(sort)
.select(projection)
.populate(population)
.exec();
res.json(users);
} catch (err) {
next(err);
}
});
app.listen(3000, () => console.log('Server running on port 3000'));