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 🙏

© 2025 – Pkg Stats / Ryan Hefner

mongodb-api-router

v1.3.2

Published

MongoDB API Router

Downloads

29

Readme

📄 mongodb-api-router Documentation

Welcome to the comprehensive documentation for mongodb-api-router, a powerful factory for creating multilingual, filterable, paginated CRUD API routes in an Express.js + Mongoose application.


📋 Table of Contents

  1. Overview
  2. Exports
  3. Localization Messages
  4. BrowserLanguage Symbol
  5. Utility Functions
  6. The apiRoute() Factory
  7. Sequence Diagram: GET Request Flow
  8. Usage Example
  9. Exceptions & Errors

1. Overview

mongodb-api-router exports:

  • A multilingual message system (messages, defineMessage, message).
  • A BrowserLanguage Symbol for locale control.
  • A default export: apiRoute(model, options) — a factory that generates Express middleware for RESTful endpoints on a given Mongoose model.

Features:

  • Automatic GET, POST, PUT, DELETE handling.
  • Filtering, pagination, field renaming and skimming (post‐query filtering).
  • Custom middleware hooks per HTTP method.
  • Error translation into multiple languages.

2. Exports

| Export | Type | Description | |--------------------|--------------|--------------------------------------------------------------| | BrowserLanguage | Symbol | Force-use a specific language instead of the browser’s. | | defineMessage | Function | Add or override localized messages by code number. | | message | Function | Retrieve a translated message (with placeholders). | | apiRoute (default) | Function | Factory to create an Express.js route handler for a Mongoose model. |


3. Localization Messages

A set of default messages keyed by numeric codes (1–11), each with translations:

| Code | English Default | |------|--------------------------------------------------------| | 1 | The request is invalid. | | 2 | You cannot filter results by the “{key}” parameter. | | 3 | The field “{target}” is required. | | 4 | The field “{target}” is too short. | | 5 | The field “{target}” is too long. | | 6 | The value of “{target}” is too low. | | 7 | The value of “{target}” is too high. | | 8 | The value of “{target}” is not valid. | | 9 | The format of “{target}” is incorrect. | | 10 | The value of “{target}” is not of the expected type. | | 11 | You cannot make this request. |

// messages structure (excerpt)
const messages = {
  __userMessages: {},
  1: { en: 'The request is invalid.', it: 'La richiesta non è valida.', /*...*/ },
  2: { en: 'You cannot filter results by the “{key}” parameter.', /*...*/ },
  // ...
  11: { en: 'You cannot make this request.', /*...*/ }
}

4. BrowserLanguage Symbol

const BrowserLanguage = Symbol('BrowserLanguage');

Use this symbol in the options.language field of apiRoute() to force all responses to a given locale, ignoring the client’s Accept-Language header.


5. Utility Functions

5.1. defineMessage(number, value)

Register or override a set of translations for message code number.

  • Parameters
    number (Number): The message code to define.
    value (Object): { [langCode]: 'Translated text', ... }.

  • Returns
    undefined (modifies internal messages.__userMessages).

defineMessage(12, {
  en: 'Custom error occurred.',
  es: 'Ocurrió un error personalizado.'
});

5.2. message(number, lang, replace)

Retrieve a translated message by code, with optional placeholder replacement.

  • Parameters
    number (Number): Message code.
    lang (String): Language code ('en', 'it', etc.).
    replace (Object): { key: 'value', target: 'fieldName' }.

  • Returns
    String: The localized, interpolated message.

message(3, 'fr', { target: 'nom' });
// → 'Le champ « nom » est requis.'

6. apiRoute() Factory

6.1. Purpose & Usage

Generate an Express middleware that provides CRUD endpoints on a Mongoose model with:

  • Query filtering & validation
  • Pagination
  • Field translation & omission
  • Per-method middleware hooks
  • Multilingual error messages
import express from 'express';
import mongoose from 'mongoose';
import apiRoute from './index.js';

const User = mongoose.model('User', new mongoose.Schema({
  name: String,
  age: Number
}));

const app = express();
app.use(express.json());

// Mount /api/users
app.use(
  apiRoute(User, {
    methods: ['GET','POST','PUT','DELETE'],
    pagesManager: { maxResults: 100 },
    acceptedQueryFields: ['name','age'],
    fields: { name: { en: 'name', it: 'nome' } },
    options: {
      POST: {
        middleware: async ({ document }) => {
          document.createdAt = Date.now();
        }
      }
    }
  })
);

app.listen(3000);

6.2. Options

| Option | Type | Default | Description | |----------------------------|----------------------------|---------------------|-------------| | model (first arg) | Mongoose Model | — | The target model for CRUD. | | filter | Function | Function[] | [] | Pre-handler checks. Return true to continue; false or object for error. | | methods | String[] | ['GET','POST','PUT','DELETE'] | Allowed HTTP methods. | | route | String | '/api/{collectionName}' | Base path ({modelName}, {collectionName} placeholders supported). | | fields | Object | null | Map model fields to custom names per locale. | | pagesManager | Object | undefined | { limit: '?limit', page: '?page', maxResults } for pagination. | | acceptedQueryFields | String[] | Object | model.schema.paths| Fields allowed in req.query / req.body. | | throwRefusedQueryFields| Boolean | true | 400 on unallowed query fields. | | language | String | Symbol | req.acceptsLanguages()[0] | Force locale if not BrowserLanguage. | | options | Object | {} | Method-specific:
| | | | • options.GET, options.POST, etc. |

6.2.1. options[method] sub‐options

| Sub‐Option | Type | Description | |---------------|-------------------------|-------------| | middleware| Function \| Function[]| Runs before saving/updating. Receives { document, req, res, next, query }. | | skimming | Function \| Function[]| Post‐query filter: return true to keep each document. |


6.3. Handler Flow

  1. Initialize options: normalize filter, methods, route.
  2. Incoming request → determine language (override if options.language !== BrowserLanguage).
  3. Merge method‐specific options[method].
  4. Parse & validate query/body via parseFilter():
    • Rename fields
    • Enforce acceptedQueryFields
    • Apply pagination parameters
  5. Run each filter function → may short‐circuit with 403/custom error.
  6. Dispatch by HTTP method:
    • GETModel.find(), optional skimming, field translation, JSON result + paging.
    • POST → new document, middleware, .save(), skimming, field translation.
    • PUT.findOneAndUpdate(), middleware({ query, set }), re‐fetch, skimming, translation.
    • DELETE → find matching docs, optional skimming, .deleteOne()/.deleteMany().

6.4. CRUD Operations

| Method | Action | Response Body | |--------|-----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------| | GET | .find(query).sort().skip().limit().lean()skimming() → translate → { ok: true, [collection]: [...] } | Results array + optional pagesManager info | | POST | new model(query).save()skimming() → translate → { ok: true, document } | Newly created document | | PUT | findOneAndUpdate(query, set) → re‐fetch → skimming() → translate → { ok: true, modelName: document } | Updated document | | DELETE | .find(query).lean()skimming() → deletion → { ok: true } | Confirmation |


6.5. Error Handling

  • Invalid options → thrown synchronously (e.g. non‐array methods, invalid route type).
  • Filter rejection403 or custom payload.
  • MongoDB ValidationError → aggregated into 400 with per‐field errors using localized messages (codes 3–10).
  • Unallowed query fields400 with error code 2.

7. Sequence Diagram: GET Request Flow

sequenceDiagram
    participant Client
    participant ExpressJS
    participant Handler as "apiRoute Handler"
    participant Model as "Mongoose Model"
    participant DB

    Client->>ExpressJS: |"GET /api/items?name=John&limit=10&page=2"|
    ExpressJS->>Handler: |"invoke apiRoute(model, options)"|
    Handler->>Handler: Determine language (Accept-Language or forced)
    Handler->>Handler: parseFilter(req.query)
    Handler->>Handler: Validate acceptedQueryFields
    Handler->>Handler: Apply pagination → limit, page
    Handler->>Handler: Execute filter functions
    Handler->>Model: find(query).sort().skip().limit()
    Model->>DB: Execute MongoDB query
    DB-->>Model: Return documents
    Model-->>Handler: Lean results
    Handler->>Handler: skimming(results)
    Handler->>Handler: Translate field names
    Handler->>Client: Return JSON `{ ok:true, items: [...], pagesManager }`

8. Usage Example

import express from 'express';
import mongoose from 'mongoose';
import apiRoute, { defineMessage, BrowserLanguage } from './index.js';

// 1. Define schema & model
const productSchema = new mongoose.Schema({
  title: String,
  price: Number,
  category: String
});
const Product = mongoose.model('Product', productSchema);

// 2. Override a default message
defineMessage(2, { en: 'Filtering by “{key}” is not permitted.' });

// 3. Create Express app
const app = express();
app.use(express.json());

// 4. Mount API route
app.use(
  apiRoute(Product, {
    methods: ['GET','POST','DELETE'],
    fields: {
      title: { en: 'title', es: 'titulo' },
      price: { en: 'price', es: 'precio' }
    },
    acceptedQueryFields: ['title','price'],
    pagesManager: { limit: '?limit', page: '?page', maxResults: 50 },
    options: {
      POST: {
        middleware: async ({ document }) => {
          // Auto‐stamp creation date
          document.createdAt = new Date();
        }
      }
    },
    language: BrowserLanguage // always use Accept-Language
  })
);

// 5. Start server
app.listen(3000, () => console.log('API listening on 3000'));

9. Exceptions & Errors

| Condition | Exception Message | |-------------------------------------------------------|-------------------------------------------------------------------------------------------| | filter not function or array of functions | apiRoute(model, { filter }) -> filter must be a function, or an array of functions | | methods not an array | apiRoute(model, { methods }) -> methods must be an array of methods | | Invalid HTTP method in methods | apiRoute(model, { methods }) -> invalid method "<METHOD>" | | route not a string | apiRoute(model, { route }) -> invalid route, it must be a string | | Unallowed query field (by default) | 400 JSON { ok:false, status:400, error: message(2) } | | MongoDB ValidationError | 400 JSON with errors: [ { target, error } ] using codes 3–10 |


Enjoy building multilingual, flexible REST APIs with zero boilerplate! 🚀