Mongoose 3.9.7 has just been released. While I did say that 3.9.6 would be the last release before 4.0.0-rc0, the MongoDB core server introduced a minor backwards-breaking change in 2.8.0-rc3. This threw a wrench into my plans to make Mongoose use v2.0 of the MongoDB NodeJS driver, which needs to account for the MongoDB server's change. In order to avoid having to introduce potentially backwards-breaking changes in a release candidate, Mongoose is postponing 4.0.0-rc0 until early 2015. Outside of upgrading to the new version of the driver, 3.9.7 is feature-complete, and packed with some very powerful new features.

A Brief Aside on Versioning in Mongoose

As an aside, starting in 4.0.0, Mongoose will move to using semantic versioning (semver) rather than its current stable/unstable versioning system. Mongoose originally used Linux-style stable/unstable versioning to ensure stability and minimize the likelihood of major bugs. However, going forward, I think semver is a better standard to ensure that mongoose remains stable while delivering new features. The trouble with even/odd versioning is that the unstable branch is effectively developed in a vacuum, as developers are discouraged from using it. Thus, when the new version is released, there are hundreds of commits in the new release that have not stood up to production-level scrutiny (mongoose 4.0.0 is currently 420 commits ahead of 3.8, and 3.8 was in turn 813 commits ahead of 3.6). Smaller, more focused releases will enable mongoose to release more features faster and minimize the amount of code change between stable releases, which in turn will lead to a more stable project.

On to the New Features

Versioning rant aside, I'm going to be writing a series of posts explaining new features in Mongoose 4. In this post, I'll highlight the results of our refactoring of Mongoose's validator system. The goal of this refactoring was to enable validators to produce richly customizable error messages, for instance, enabling you to associate an HTTP status code with a validation error. How does this work in practice? Suppose you define a schema with a custom validator:

var breakfastSchema = new mongoose.Schema({
  description: {
    type: String,
    validate: [{
      validator: function(v) {
        return v.length <= 70;
      },
      msg: 'Error code: {ERRORCODE} for value "{VALUE}"',
      errorCode: 25
    }]
  }
});

Now, suppose you have a document with the above schema, and you set the description to something longer than 70 characters:

doc.description = '';
for (var i = 0; i < 7; ++i) {
  doc.description += '6chars'; // total 72 characters
}

doc.validate(function(error) {
  // error.errors['description'].toString() will equal:
  // 'Error code: 25 for value "6chars..."'
});

The validator properties aren't only accessible in the message. They're also added to the resulting error object:

// The http-status module includes a map of HTTP statuses
var status = require('http-status');

var breakfastSchema = new mongoose.Schema({
  description: {
    type: String,
    validate: [{
      validator: function(v) {
        return v.length <= 10;
      },
      http: status.FORBIDDEN // HTTP 403
    }]
  }
});

// ...

doc.description = 'this is longer than 10 chars';
doc.validate(function(error) {
  // error.errors['description'].http is equal to
  // status.FORBIDDEN (403)
});

This feature is relatively small, but is exceptionally useful in allowing you to attach custom properties to validation errors. The next post, in early January, will cover a much larger topic: using Mongoose 4's in-browser schema validation with AngularJS.

Found a typo or error? Open up a pull request! This post is available as markdown on Github
comments powered by Disqus