Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS Mongoose Schema 'save' function error handling?

I am having a problem outputting an error to the user using res.send(err), which is being called in the callback of the Mongoose User Schemas 'save' function. I would like to note that when I use console.log(err), it show's the expected error (such as username is too short), but res.send is outputting '{}' in PostMan when sending a request with POST values that should cause an error.

Also I am wondering if I should be doing input validation in my router or in my Mongoose user schemas .pre function? Putting validation there seems correct, as it keeps my Node router file much cleaner.

Here is the code in question...

app/routes/apiRouter.js

var User = require('../models/User');
var bodyParser = require('body-parser');
...
apiRouter.post('/users/register', function(req, res, next) {


    var user = new User;
    user.name = req.body.name;
    user.username = req.body.username;
    user.password = req.body.password;

    user.save(function(err) {
        if (err) {
            console.log(err);
            res.send(err);
        } else {
            //User saved!
            res.json({ message: 'User created' });
        }
    });

});
...

app/models/User.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');
var validator = require('validator');

var UserSchema = new Schema({
    name: String,
    username: { type: String, required: true, index: {unique: true} },
    password: { type: String, required: true, select: false }
});

UserSchema.pre('save', function(next) {
    var user = this;

    if (!validator.isLength(user.name, 1, 50)) {
        return next(new Error('Name must be between 1 and 50 characters.'));
    }

    if (!validator.isLength(user.username, 4, 16)) {
        return next(new Error('Username must be between 4 and 16 characters.'));
    }

    if (!validator.isLength(user.password, 8, 16)) {
        return next(new Error('Password must be between 8 and 16 characters.'));
    }

    bcrypt.hash(user.password, false, false, function(err, hash) {
        user.password = hash;
        next();
    });
});

UserSchema.methods.comparePassword = function(password) {
    var user = this;
    return bcrypt.compareSync(password, user.password);
};

module.exports = mongoose.model('User', UserSchema);
like image 440
JohnWick Avatar asked Jul 23 '15 13:07

JohnWick


1 Answers

From a quick glance, it looks like you are using express. When an object or array is passed to res.send() (like in the case an error occurs), it defaults to using JSON.stringify on the object/array and sets the content-type to application/json. (Ref: http://expressjs.com/4x/api.html#res.send). The message property of an Error object is not serialized when it is passed through JSON.stringify because it is defined with enumerable being false.

Ex.

 $ node
 > var err = new Error('This is a test')
 undefined
 > console.log(JSON.stringify(err))
 {}
 undefined

Is it not possible to stringify an Error using JSON.stringify? has some examples of how to make sure the message property (and others if that is what you would like) are included.

like image 52
Evan Lucas Avatar answered Oct 14 '22 07:10

Evan Lucas