Skip to content
This repository

Mongoose Express Rest Service

branch: master


latest commit 93c01c01c5
Justin authored
Octocat-spinner-32 example test invalid PUT November 26, 2013
Octocat-spinner-32 lib *fixed git single January 26, 2014
Octocat-spinner-32 test *small fixes to single item handling. December 15, 2013
Octocat-spinner-32 .gitignore Added ignore September 12, 2012
Octocat-spinner-32 Update December 01, 2013
Octocat-spinner-32 index.js first commit February 27, 2012
Octocat-spinner-32 mocha-run.js *fixing mers for express3. September 12, 2012
Octocat-spinner-32 package.json 0.7.3 March 09, 2014
Octocat-spinner-32 ws-run.js *addressing #10 September 08, 2013


*Mongoose *Express *Rest *Service

Mers is a plugin for express to expose mongoose finders as simple crud/rest operations.  The
basic idea being you should just define your model/finders and the rest should be be magic.

Usage [usage]

    var mers = require('mers');
    app.use('/rest', mers({uri:'mongodb://localhost/rest_example_prod'}).rest());

Configuration options include:

  • uri:uri://mongoose (as shown above)
  • mongoose:mongoose (your mongoose instance)
  • [error][error]:function (your custom error handler)
  • responseStream:function (your custom respost stream. See: lib/streams.js)
  • transformer:function (your custom transformer factory)

If you had a schema such as

var mongoose = require('mongoose'), Schema = mongoose.Schema,
    ObjectId = mongoose.Schema.ObjectId;

var CommentSchema = new Schema({
    title:String, body:String, date:Date

var BlogPostSchema = new Schema({
    author:ObjectId, title:String, body:String, buf:Buffer, date:Date, comments:[CommentSchema], meta:{
        votes:Number, favs:Number
 * Note this must return a query object.   If it doesn't well, I dunno what it'll do.
 * @param q
 * @param term
BlogPostSchema.statics.findTitleLike = function findTitleLike(q, term) {
    return this.find({'title':new RegExp(q.title || term, 'i')});
var Comment = module.exports.Comment = mongoose.model('Comment', CommentSchema);
var BlogPost = module.exports.BlogPost = mongoose.model('BlogPost', BlogPostSchema);

you could then access it at listing.



Pagination is also supported via skip= and limit= query params.



Mongoose populate is supported, but this will be changing shortly to allow for more fine grained controll over population. Currently you can do


or to specify particular fields.



Filtering is available for strings. To find all the blog posts with C in the title.


Also you can and or nor the filters by using + (and) - (nor) or nothing or http://localhost:3000/rest/blogpost?filter[-title]=C http://localhost:3000/rest/blogpost?filter[+title]=C&filter[-body]=A

To filter all String fields that have a C in them



Sorting is supported 1 ascending -1 ascending.



Transformers can be registered on startup. A simple TransformerFactory is included. Something that takes security into account could be added. Currently this is only supported on the get operations. May change the responses to post to send location, though I find that pretty inconvient.

app.use('/rest', require('mers').rest({
           renameid:function(Model, label){
            //do some setup but return function.
              return function(obj){
       = obj._id;
                delete obj._id;
                //don't forget to return the object.  Null will filter it from the results.
                return obj;

to get results transformered just add


It handles get/put/post/delete I'll add some docs on that some day, but pretty much as you expect, or I expect anyways. see tests/routes-mocha.js for examples.

Static Finders

It should also be able to be used with Class finders. Now handles class finders. Note: They must return a query object. They are passed the query object and the rest of the url. All of the populate's, filters, transforms should work.

 * Note this must return a query object.
 * @param q
 * @param term
BlogPostSchema.statics.findTitleLike = function findTitleLike(q, term) {
    return this.find({'title':new RegExp(q.title || term, 'i')});

So you can get the url




[Error Handling][error]

To create a custom error handler

   app.use('/rest, rest({
         error : function(err, req, res, next){
                   error:err && err.message

Custom Transformers

You can transform your results by adding a custom transformer and or adding a new TransformerFactory

   app.use('/rest, rest({
         transformers :{
          cooltranform:function(Model, label){
             return function(obj){
           = obj._id;
                    delete obj._id;
                    return obj; //returning null removes it from the output
          } }).rest());


Selecting support is upcoming, but for now you can do it in finders

 var User = new Schema({
 User.statics.selectJustIdAndUsername  = function(){
  this.find({}).select('_id username');

Custom ResultStream

You can create your own result stream. It needs to subclass Stream and be writable. This can allow for other formats, and preventing the wrapping of data in the payload.


An example of a customized rest service can be found at
Something went wrong with that request. Please try again.