mongodb-api-router
v1.3.2
Published
MongoDB API Router
Downloads
29
Maintainers
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
- Overview
- Exports
- Localization Messages
- BrowserLanguage Symbol
- Utility Functions
- The
apiRoute()Factory - Sequence Diagram: GET Request Flow
- Usage Example
- Exceptions & Errors
1. Overview
mongodb-api-router exports:
- A multilingual message system (
messages,defineMessage,message). - A
BrowserLanguageSymbol 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 internalmessages.__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
- Initialize options: normalize
filter,methods,route. - Incoming request → determine language (override if
options.language !== BrowserLanguage). - Merge method‐specific
options[method]. - Parse & validate query/body via
parseFilter():- Rename fields
- Enforce
acceptedQueryFields - Apply pagination parameters
- Run each
filterfunction → may short‐circuit with 403/custom error. - Dispatch by HTTP method:
- GET →
Model.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().
- GET →
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, invalidroutetype). - Filter rejection →
403or custom payload. - MongoDB ValidationError → aggregated into
400with per‐field errors using localized messages (codes 3–10). - Unallowed query fields →
400with 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! 🚀
