Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
hack to determine whether an error is a validation error from waterline (for Sails/Waterline 0.9.x)
var _ = require('lodash');
/**
* `isValidationError`
*
* Is this a waterline validation error?
*/
function isWaterlineValidationError (err) {
if (_.isPlainObject(err)) {
var keys = Object.keys(err);
if (keys.length) {
var failedValidation = err[keys[0]];
if (_.isArray(failedValidation) && failedValidation.length &&
_.isPlainObject(failedValidation[0]) && failedValidation[0]['rule']
) {
return true;
}
}
}
if ( _.isString(err) && err.match(/duplicate key value violates unique constraint/g) ) {
return true;
}
if ( _.isString(err) && err.match(/^Bad request/ig)) {
return true;
}
return false;
}
@mikermcneil

This comment has been minimized.

Copy link
Owner Author

commented Jan 11, 2014

@mikermcneil

This comment has been minimized.

Copy link
Owner Author

commented Jan 11, 2014

Also

/**
 * Takes a Sails Model object (e.g. User) and a ValidationError object and translates it into a friendly
 * object for sending via JSON to client-side frameworks.
 *
 * To use add a new object on your model describing what validation errors should be translated:
 *
 * module.exports = {
 *   attributes: {
 *     name: {
 *       type: 'string',
 *       required: true
 *     }
 *   },
 * 
 *   validation_messages: {
 *     name: {
 *       required: 'you have to specify a name or else'
 *     }
 *   }  
 * };
 *
 * Then in your controller you could write something like this:
 *
 * var validator = require('sails-validator-tool');
 *
 * Mymodel.create(options).done(function(error, mymodel) {
 *   if(error) {
 *     if(error.ValidationError) {
 *       error_object = validator(Mymodel, error.Validation);
 *       res.send({result: false, errors: error_object});
 *     }
 *   }
 * });
 *
 * @param model {Object} An instance of a Sails.JS model object.
 * @param validationErrors {Object} A standard Sails.JS validation object.
 *
 * @returns {Object} An object with friendly validation error conversions.
 */ 
module.exports = function(model, validationError) {
  var validation_response = {};
  var messages = model.validation_messages;
  validation_fields = Object.keys(messages);

  validation_fields.forEach(function(validation_field) {

    if(validationError[validation_field]) {
      var processField = validationError[validation_field];
      //console.log(processField);
      processField.forEach(function(rule) {
        if(messages[validation_field][rule.rule]) {
          if(!(validation_response[validation_field] instanceof Array)) {
            validation_response[validation_field] = new Array();
          }

          var newMessage={};
          newMessage[rule.rule] = messages[validation_field][rule.rule];
          validation_response[validation_field].push(newMessage);
        }
      });

    }
  });

  return validation_response;
};
@afonsomota

This comment has been minimized.

Copy link

commented Jan 31, 2014

Thanks. This code on the last comment is great.

It makes it easier to translate error messages with i18n also.

@mikermcneil

This comment has been minimized.

Copy link
Owner Author

commented Feb 11, 2014

@afonsomota np! It's actually not mine, so I can't take the credit. Someone shared it in IRC-- wish I could remember who... :\

@johnnncodes

This comment has been minimized.

Copy link

commented Feb 12, 2014

I think its _sfb. Anyway, I'm also using that solution to provide custom validation messages, but the problem is if you didn't provide a custom validation message to some fields, only the fields where you provided a custom validation message will have error messages :/

Anyone have other solutions or improvements on the current solution above?

I hope custom validation messages will really be supported really soon - balderdashy/sails#1173

@danegigi

This comment has been minimized.

Copy link

commented Mar 7, 2014

Here's my version of the code above to generate generic error message if no custom message defined.

/**
 * Takes a Sails Model object (e.g. User) and a ValidationError object and translates it into a friendly
 * object for sending via JSON to client-side frameworks.
 *
 * To use add a new object on your model describing what validation errors should be translated:
 *
 * module.exports = {
 *   attributes: {
 *     name: {
 *       type: 'string',
 *       required: true
 *     }
 *   },
 *
 *   validation_messages: {
 *     name: {
 *       required: 'you have to specify a name or else'
 *     }
 *   }
 * };
 *
 * Then in your controller you could write something like this:
 *
 * var validator = require('sails-validator-tool');
 *
 * Mymodel.create(options).done(function(error, mymodel) {
 *   if(error) {
 *       error_object = validator(Mymodel, error);
 *       res.send({result: false, errors: error_object});
 *   }
 * });
 *
 * @param model {Object} An instance of a Sails.JS model object.
 * @param validationErrors {Object} A standard Sails.JS validation object.
 *
 * @returns {Object} An object error messages in array.
 * NOTE:
 *   ARRANGEMENT OF ERROR MESSAGES WILL FOLLOW HOW YOU DEFINE YOUR FIELD
 */

module.exports = function(model, err){
  if(!err.ValidationError) return

  var validationError = err.ValidationError;
  var custom_messages = model.validation_messages;
  var error_fields = Object.keys(validationError);
  var error_messages = {};

  error_fields.forEach(function(field){
    error_messages[field] = new Array();

    field_messages = custom_messages[field]
    validationError[field].forEach(function(err){
      if(!field_messages) error_messages[field].push(field + " should be " + err.rule);
      else{
        error_message = field_messages[err.rule]? field_messages[err.rule] : (field + " should be " + err.rule);
        error_messages[field].push(error_message)
      }

    });
  });

  return error_messages;
}
@mikermcneil

This comment has been minimized.

Copy link
Owner Author

commented Mar 27, 2014

@danegigi @basco-johnkevin @afonsomota Hey y'all- check out the latest version of Sails/Waterline on master branch on github. Waterline errors have been normalized into a more predictable format. Still needs some work/testing, but the situation is much better now.

@dezull

This comment has been minimized.

Copy link

commented Nov 26, 2014

@mikermcneil Is okay to just check e.code ? as on master

  if (e.code && e.code === 'E_VALIDATION') {
    // var validationErrors = e.invalidAttributes;
  }
@lykmapipo

This comment has been minimized.

Copy link

commented Feb 12, 2015

For sails v0.11.X you may use this sails-hook-validation

@mrTimofey

This comment has been minimized.

Copy link

commented May 20, 2015

More compact solution

function(err, model) {
    // no errors
    if (!err) return true;
    // error is not a validation error
    if (!err.ValidationError) return false;
    // { field: { rule: 'Message', otherRule: 'Message' ... } ... }
    var messages = model.validationMessages,
        errors = err.ValidationError,
        output = {};

    Object.keys(errors).forEach(function(field) {
        output[field] = [];
        errors[field].forEach(function(error) {
            output[field].push(messages[field] && messages[field][error.rule] || error.rule);
        })
    });

    return output;
}
@mikermcneil

This comment has been minimized.

Copy link
Owner Author

commented Feb 13, 2017

Note that in Sails v1 this is changing a bit. For details, see the docs on sailsjs.com (or balderdashy/sails#3459 (comment) for a bit more background)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.