validations: include more details in `err.message`

Modify ValidationError constructor to include the model name and
a human-readable representation of the validation errors (messages)
in the error message.

Before this change, the message was pointing the reader
to `err.details`.  Most frameworks (e.g. express, mocha) log only
`err.message` but not other error properties, thus the logs were
rather unhelpful.

Example of the new error message:

    The `User` instance is not valid. Details: `name` can't be blank.
This commit is contained in:
Miroslav Bajtoš 2014-05-20 10:47:44 +02:00 committed by Raymond Feng
parent a9a7ab1315
commit 65fa7a1c00
2 changed files with 44 additions and 3 deletions

View File

@ -687,12 +687,18 @@ function ValidationError(obj) {
if (!(this instanceof ValidationError)) return new ValidationError(obj); if (!(this instanceof ValidationError)) return new ValidationError(obj);
this.name = 'ValidationError'; this.name = 'ValidationError';
this.message = 'The Model instance is not valid. ' +
'See `details` property of the error object for more info.'; var context = obj && obj.constructor && obj.constructor.modelName;
this.message = util.format(
'The %s instance is not valid. Details: %s.',
context ? '`' + context + '`' : 'model',
formatErrors(obj.errors) || '(unknown)'
);
this.statusCode = 422; this.statusCode = 422;
this.details = { this.details = {
context: obj && obj.constructor && obj.constructor.modelName, context: context,
codes: obj.errors && obj.errors.codes, codes: obj.errors && obj.errors.codes,
messages: obj.errors messages: obj.errors
}; };
@ -701,3 +707,19 @@ function ValidationError(obj) {
} }
util.inherits(ValidationError, Error); util.inherits(ValidationError, Error);
function formatErrors(errors) {
var DELIM = '; ';
errors = errors || {};
return Object.getOwnPropertyNames(errors)
.filter(function(propertyName) {
return Array.isArray(errors[propertyName]);
})
.map(function(propertyName) {
var messages = errors[propertyName];
return messages.map(function(msg) {
return '`' + propertyName + '` ' + msg;
}).join(DELIM);
})
.join(DELIM);
}

View File

@ -111,6 +111,25 @@ describe('validations', function () {
done(); done();
}); });
it('should include validation messages in err.message', function(done) {
delete User._validations;
User.validatesPresenceOf('name');
User.create(function (e, u) {
should.exist(e);
e.message.should.match(/`name` can't be blank/);
done();
});
});
it('should include model name in err.message', function(done) {
delete User._validations;
User.validatesPresenceOf('name');
User.create(function (e, u) {
should.exist(e);
e.message.should.match(/`User` instance/i);
done();
});
});
}); });
}); });