Mongoose Rest Query

Restify your mongoose model


Mongoose Rest Query

Overview

Mongoose Rest Query makes the creation of rest api in mongoose a breeze. It automatically create CRUD routes up to two levels deep and provide a built-in mechanism to connect to multiple mongo databases.

Installation

npm install mongoose-rest-query --save
npm install mongoose-auto-number --save

Quick Start

Consider the following snippet

const express = require('express');
const mongoose = require('mongoose');
const mrq = require('mongoose-rest-query')

mongoose.Promise = global.Promise;

const Schema = mongoose.Schema;

const userSchema = new Schema({
    email: String,
    firstname: String,
    lastname: String,
    age: Number
});

const models = {
    User: userSchema
};

mrq.config.modelSchemas = models;
mrq.config.dbPath = 'mongodb://localhost/restifydb';

const app = express();

app.use(mrq.db);

const restify = mrq.restify;

app.use('/api/users', restify('User'));

app.listen(9000, () => {
    console.log('Server is listening on port 9000');
});

The above snippet automatically generates the following api endpoints

  • GET http://localhost:9000/api/users -> List all users (subject to filter criteria)
  • POST http://localhost:9000/api/users -> Create new user or users, can accept an object or array
  • DELETE http://localhost:9000/api/users -> Delete all users (subject to filter criteria)
  • GET http://localhost:9000/api/users/count -> Get total count (subject to filter criteria)
  • GET http://localhost:9000/api/users/:id -> Get user by id (can apply populate or select in query)
  • PUT http://localhost:9000/api/users/:id -> Update user by id (also accept partial object)
  • DELETE http://localhost:9000/api/users/:id -> Delete user by id
  • POST http://localhost:9000/api/users/aggregate -> Accept mongo aggregrate pipelines as body for rich aggregation

Note: additional crud routes are generated if the object contain a field which is of type array of objects

Query parameters

In addition to the routes generated, certain endpoints also accept query parameters which provide a rich mechanism for filtering, sorting and paginating.

  • Filtering
    • GET /api/users?email=adarsh@github.com -> exact match
    • GET /api/users?email=~adarsh -> containing
    • GET /api/users?age=>20 -> greater than 20
    • GET /api/users?age=>=20 -> greater than or equal 20
    • GET /api/users?age=<20 -> less than 20
    • GET /api/users?age=<=20 -> less than or equal 20
    • GET /api/users?age=>10&age=<=20 -> greater than 10 and less than or equal 20
    • GET /api/users?age=!=20 -> not equal 20
    • GET /api/users?age=!in=20,21,22 -> not equal 20, 21 or 22
    • GET /api/users?age=in=20,21,22 -> equal 20, 21 or 22
  • Sorting
    • GET /api/users?sort=email -> sort by email asc
    • GET /api/users?sort=-email -> sort by email desc
  • Fields projection
    • GET /api/users?select=email -> return only email
  • Mongoose Populate
    • GET /api/users?populate=referenceField -> Populate the referencField
  • Pagination
    • GET /api/users?limit=10 -> list only 10 users
    • GET /api/users?limit=10&skip=0 -> list only first 10 users
    • GET /api/users?limit=10&skip=10 -> list the 11th to 20th users

Activating the multi database mode

In order to use the multi db mode, we need to have a strategy to identify request in order to use the correct database. In the example below, an indentifier shall be used in the request header (x-client-id)

Consider the following snippet

const express = require('express');
const mongoose = require('mongoose');
const mrq = require('mongoose-rest-query')

mongoose.Promise = global.Promise;

const Schema = mongoose.Schema;

const userSchema = new Schema({
    email: String,
    firstname: String,
    lastname: String,
    age: Number
});

const models = {
    User: userSchema
};

mrq.config.modelSchemas = models;
mrq.config.multiDB = true;

const app = express();

//middleware to check client id and set to correct db path
app.use(function(req, res, next){

    if(req.headers['x-client-id'] === 'client1')
        req.headers['x-client-mongodb-path'] = 'mongodb://localhost/client1';
    
    else if(req.headers['x-client-id'] === 'client2')
        req.headers['x-client-mongodb-path'] = 'mongodb://localhost/client2';
    
    else
        res.status(401).send('Invalid client id');

    next();
});

app.use(mrq.db);

const restify = mrq.restify;

app.use('/api/users', restify('User'));

app.listen(9000, () => {
    console.log('Server is listening on port 9000');
});

Accessing the mongoose model in a custom route


app.get('/api/custom', function(req, res){

    const User = mrq.model(req, 'User'); //this return the mongoose model

    User.find(function(err, users){

        if(err)
            res.status(500).send(err);
        else
            res.send(users);
    });

});