vanta-api
v1.3.2
Published
Advanced API features and security configuration for Node.js/MongoDB.
Downloads
83
Maintainers
Readme
VantaApi :: Advanced MongoDB API Utilities
VantaApi is a comprehensive toolkit for building secure, performant, and flexible APIs on top of MongoDB with Mongoose. It streamlines common query operations—filtering, sorting, field selection, pagination, and population—while enforcing robust security policies and sanitization.
📦 Installation
Install via npm or Yarn:
npm install vanta-api
# or
yarn add vanta-apiA postinstall hook will scaffold a security-config.js file in your project root.
⚙️ Setup & Initialization
1. Importing the Package
ECMAScript Module (ESM)
import express from 'express';
import mongoose from 'mongoose';
import ApiFeatures, { catchAsync, catchError, HandleERROR } from 'vanta-api';CommonJS (CJS)
const express = require('express');
const mongoose = require('mongoose');
const { default: ApiFeatures, catchAsync, catchError, HandleERROR } = require('vanta-api');2. Basic Server Setup
const app = express();
app.use(express.json());
// Connect to MongoDB
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});3. Route Definition & Error Handling
// Example route with async handler
app.get(
'/api/v1/items',
catchAsync(async (req, res, next) => {
const result = await new ApiFeatures(ItemModel, req.query, req.user.role)
.filter()
.sort()
.limitFields()
.paginate()
.populate()
.execute();
res.status(200).json(result);
})
);
// Global error handler (after all routes)
app.use(catchError);
// Start server
app.listen(3000, () => {
console.log('Server running on port 3000');
});🔍 API Reference
1. catchAsync(fn)
Wraps an async function to catch errors and pass them to Express error middleware.
Signature:
catchAsync(fn: Function): FunctionExample:
app.post( '/api/v1/users', catchAsync(async (req, res) => { // async logic }) );
2. catchError(err, req, res, next)
Express error-handling middleware that returns standardized JSON errors.
Response:
{ "status": "error" | "fail", "message": "Error description", "errors": [ /* optional array of details */ ] }Usage: Place after all routes
3. HandleERROR
Custom Error subclass for operational errors.
Constructor:
new HandleERROR(message: string, statusCode: number)Example:
if (!user) { throw new HandleERROR('User not found', 404); }
🚀 ApiFeatures Class
Chainable class that translates HTTP query parameters into a secure MongoDB aggregation pipeline.
const features = new ApiFeatures(
Model, // Mongoose model
req.query, // HTTP query object
req.user.role // User role for security (guest|user|admin|superAdmin)
)
.filter() // Filtering
.sort() // Sorting
.limitFields() // Field limiting
.paginate() // Pagination
.populate() // Population
.addManualFilters({ isActive: true }) // Manual filters
;
const result = await features.execute({ allowDiskUse: true });Constructor
new ApiFeatures(
model: mongoose.Model,
queryParams: Record<string, any> = {},
userRole: string = 'guest'
)- model: Mongoose model.
- queryParams: Typically
req.query. - userRole: Role key for security rules.
Chainable Methods
| Method | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| .filter() | Applies MongoDB operators. Supported operators: |
| | eq, ne, gt, gte, lt, lte, in, nin, regex (e.g. ?price[gt]=100&name[regex]=Book). |
| .sort() | Sorting (e.g. ?sort=price,-name). |
| .limitFields() | Field selection (e.g. ?fields=name,price). |
| .paginate() | Pagination (e.g. ?page=2&limit=10). |
| .populate(paths?) | Populate referenced documents. Accepts various input types (see below). |
| .addManualFilters(obj) | Add programmatic filters (e.g. .addManualFilters({ isActive: true })). |
All methods return
thisfor chaining.
Populate Input Formats
The .populate() method supports multiple ways to specify which paths to populate:
String (comma-separated)
.populate('author,comments')Array of strings
.populate(['author', 'comments'])Dot notation for nested paths
// Populating nested field 'comments.author' .populate('comments.author')Object with options
.populate({ path: 'author', // field to populate select: 'name email', // include only name and email match: { isActive: true}, // only active authors options: { limit: 5 } // limit populated docs })Array of objects
.populate([ { path: 'author', select: 'name' }, { path: 'comments', match: { flagged: false } } ])
execute(options)
Executes aggregation pipeline. (options)
Executes aggregation pipeline.
Signature:
async execute(options?: { useCursor?: boolean; // return cursor if true allowDiskUse?: boolean; // enable disk use projection?: Record<string, any>; // manual projection map }): Promise<{ success: boolean; count: number; data: any[]; }>```Example Response:
{ "success": true, "count": 50, "data": [ /* documents */ ] }
🔐 Security Configuration
Customize rules in security-config.js at your project root (auto-generated):
// security-config.js
export const securityConfig = {
allowedOperators: [
'eq','ne','gt','gte','lt','lte','in','nin','regex'
],
forbiddenFields: ['password','__v'],
accessLevels: {
guest: {
maxLimit: 20,
allowedPopulate: []
},
user: {
maxLimit: 100,
allowedPopulate: ['orders','profile']
},
admin: {
maxLimit: 1000,
allowedPopulate: ['*']
}
}
};- allowedOperators: Operators users can use in queries.
- forbiddenFields: Fields excluded from results.
- accessLevels: Per-role limits and populate permissions.
If you omit
security-config.js, defaults are applied from the package.
🔍 Examples
Filter with Multiple Operators
GET /api/v1/products?price[gte]=50&price[lte]=200&category[in]=["books","electronics"]Manual Filter & Projection
const features = new ApiFeatures(Product, req.query, 'user')
.addManualFilters({ isActive: true })
.filter()
.limitFields()
.execute({ projection: { name: 1, price: 1 } });Populate Relations
GET /api/v1/posts?populate=author,commentsComplete Controller Example
app.get(
'/api/v1/orders',
catchAsync(async (req, res) => {
const result = await new ApiFeatures(Order, req.query, req.user.role)
.filter()
.sort()
.limitFields()
.paginate()
.populate()
.execute();
res.json(result);
})
);🧪 Testing
npm testTests use Jest. Add tests for your controllers and ApiFeatures behaviors.
📜 License
MIT © Alireza Aghaee
📜 License
MIT © 2024 Alireza Aghaee
✒️ Author
Alireza Aghaee
- GitHub: AlirezaAghaee1996
- LinkedIn: alireza-aghaee-mern-dev
