Why did validator remove chaining? I've been looking for validation similar to chai but with more advanced features for data validation. I saw a stack overflow post referencing node-validator, which led me here. To my disappointment, chaining had been depreciated.
Is it still possible to chain? What was the reason for removing it?
It kind of seems like a step backward to go from this code:
var check = require('validator').check;
check('[email protected]').isEmail().len(6, 64);
to this code:
var check = require('validator');
check.isEmail('[email protected]');
check.isLength('[email protected]', 6, 64);
Care to explain the decision for this?
never mind, joi has what I'm looking for.
Most people preferred
if (the_data_is_valid) {
// do something if valid
} else {
// do something if invalid
}
compared to
try {
// check the data is valid
// do something if valid
} catch (err) {
// do something if invalid
}
The latter is error prone since the // do something if valid block is within the try..catch and it might raise an error. JavaScript is missing a try..catch..else construct that would help here.
The library is supposed to be low-level validation building blocks. Chaining can be added easily:
var validator = require('validator');
function ValidatorChain(str) {
this.str = str;
}
Object.keys(validator).forEach(function (fn) {
ValidatorChain.prototype[fn] = function () {
var args = Array.prototype.slice.call(arguments);
args.unshift(this.str);
if (!validator[fn].apply(validator, args))
throw Error(fn + ' failed with ' + this.str);
return this;
};
});
exports.check = function (str) {
return new ValidatorChain(str);
};
check('[email protected]').isEmail().isLength(5, 64);
It would be nice if both options were available. I use promises and would prefer it to throw when something is invalid. I'm assuming it would be an easy fix to have both options.
There are different requirements when it comes to chaining. Some want the chain to throw as soon as a validation error occurs, while others want to collect all errors and then access them at the end so they can be displayed to a user, e.g. web parameter validation.
You're free to use and modify the snippet above to fit your use case.
Still, I feel like having both the ability to chain and not to chain would be the best case. Adding that extra snippet of code to allow chaining is kind of bulky.
I feel like it would be cleaner to have some sort of chaining parameter to allow for it.
Chaining could be invoked by something like this:
var check = require('validator').chain;
check('[email protected]').isEmail().len(6, 64);
notice the .chain so a user can specify if they would like chaining.
Just put the snippet of code you have inside validator rather than the user doing it in their own code.
As of right now, there aren't any good chaining libraries available. Joi doesn't have quite the same amount of features.
But which chaining style to employ? As I said, there are multiple use cases here. Hacks were added over the years to accommodate multiple chaining styles, but then I abandoned the idea and chose to go lower level so that users could implement the chaining style _they_ wanted.
If it was promised based you could do something like this:
check('[email protected]').isEmail().len(6, 64).then(function(email){
// do something with email
}).catch(function(error){
// do something if invalid
})
This solves your try..catch..else problem... but I probably can't change your mind, can I?
You missed my point with the last few messages. The primary use case for the library (at least, from the GitHub issues that have been raised) seems to be web parameter validation, where it's best practice to show the user _all_ of the validation errors that occurred, rather than just one at a time.
For example, if you're validating a password and need it to be a) a certain length, b) have no special characters, and c) require at least one letter and one number, then you might come up with something like this:
check(password).isLength(5, 10).matches(/[a-z]/i).matches(/\d/).matches(/^[a-z0-9_-]+$/i);
The problem with your chaining approach is that an error is thrown when the first validation error occurs; the remaining validators are skipped. If the user enters !@#$ as a password then they'll only be informed that it's too short, not that it's too short and contains invalid characters, etc. Multiple form submissions are required to fix all errors; this is bad practice.
At one stage there were two helpers functions that changed the chaining style so that it collected errors rather than throwing them:
var chain = check(password).collectErrors()
chain.isLength(5, 10).matches(/[a-z]/i).matches(/\d/).matches(/^[a-z0-9_-]+$/i)
var errors = chain.getErrors();
People then started complaining that they couldn't customize the error messages of individual validators when using this chaining style. Eventually I decided to drop chaining all together since there are multiple use cases and no "right" way to chain.
Contrast this with the current version of the library:
var errors = [];
if (!validator.isLength(password, 5, 10))
errors.push('Password must be between 5 and 10 characters');
if (!validator.matches(password, /[a-z]/i))
errors.push('Password must contain a letter');
if (!validator.matches(password, /\d/i))
errors.push('Password must contain a number');
if (!validator.matches(password, /^[a-z0-9_-]+$/i))
errors.push('Password can only contain alphanumeric characters, underscores and hyphens');
You get much better control over error messages, and can pass all validation errors to the user so that they can fix all issues at once.
That makes sense, thanks for the clarification. :)
Glad I searched through the closed Issues to find this, but I have another comment on this in regards to the functions that return a string vs. boolean. I think it should definitely be possible to chain the methods that return a string since it would just apply a new string function to each modified string. 馃憤
Thanks a lot for elaborating @chriso.
Probably not the best design, but here is a demo with "chaining" using input data attributes:
https://codepen.io/oshihirii/pen/xjqmdw
Thanks for providing general example of errors.push() @chriso.
Most helpful comment
You missed my point with the last few messages. The primary use case for the library (at least, from the GitHub issues that have been raised) seems to be web parameter validation, where it's best practice to show the user _all_ of the validation errors that occurred, rather than just one at a time.
For example, if you're validating a password and need it to be a) a certain length, b) have no special characters, and c) require at least one letter and one number, then you might come up with something like this:
The problem with your chaining approach is that an error is thrown when the first validation error occurs; the remaining validators are skipped. If the user enters
!@#$as a password then they'll only be informed that it's too short, not that it's too short and contains invalid characters, etc. Multiple form submissions are required to fix all errors; this is bad practice.At one stage there were two helpers functions that changed the chaining style so that it collected errors rather than throwing them:
People then started complaining that they couldn't customize the error messages of individual validators when using this chaining style. Eventually I decided to drop chaining all together since there are multiple use cases and no "right" way to chain.
Contrast this with the current version of the library:
You get much better control over error messages, and can pass all validation errors to the user so that they can fix all issues at once.