npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vanta-api

v1.3.2

Published

Advanced API features and security configuration for Node.js/MongoDB.

Downloads

83

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-api

A 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): Function

  • Example:

    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 this for chaining.

Populate Input Formats

The .populate() method supports multiple ways to specify which paths to populate:

  1. String (comma-separated)

    .populate('author,comments')
  2. Array of strings

    .populate(['author', 'comments'])
  3. Dot notation for nested paths

    // Populating nested field 'comments.author'
    .populate('comments.author')
  4. 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
    })
  5. 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,comments

Complete 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 test

Tests use Jest. Add tests for your controllers and ApiFeatures behaviors.


📜 License

MIT © Alireza Aghaee


📜 License

MIT © 2024 Alireza Aghaee


✒️ Author

Alireza Aghaee