Object validation in JavaScript can be tedious if you don't have a good framework in place. In this post, we'll use the Array.reduce
method to make object validation feel like a treat!
Manual Validations
Let's say we have a user
object and several criteria that need to pass to make it valid. Here are the properties and the criteria that they must meet:
prop | criteria |
---|---|
name | Longer than 2 characters |
password | Longer than 8 characters |
confirmPassword | Matches the password |
age | 18 or greater |
If we were to take a somewhat manual approach to validation, we might write something like this:
const user = {
name: "Bob",
password: "kaBob123",
confirmPassword: "kaBob123",
age: 19,
};
const errors = [];
if (user.name.length < 2) {
errors.push("User's name is too short");
}
if (user.password.length < 8) {
errors.push("User's password is too short");
}
if (user.password !== user.confirmPassword) {
errors.push("Password and confirmation do not match");
}
if (user.age < 18) {
errors.push("User must be at least 18 years old");
}
const isValid = errors.length === 0;
Our errors
array would get populated with any validation errors and, if the array had a length greater than 0, our isValid
variable would be false
.
Creating a Validation Framework
While this works alright for a small number of validations, I tend to prefer organizing larger sets of rules in an array, and using the reduce
method to determine if there are errors:
// Validation rules
const rules = [
{
test: (user) => user.name.length > 2,
message: "User's name is too short",
},
{
test: (user) => user.password.length >= 8,
message: "User's password is too short",
},
{
test: (user) => user.password === user.confirmPassword,
message: "Password and confirmation do not match",
},
{
test: (user) => user.age >= 18,
message: "User must be at least 18 years old",
},
];
// Test object against rules
const errors = rules.reduce((errs, rule) => {
const result = rule.test(user);
if (result === false) {
errs.push(rule.message);
}
return errs;
}, []);
const isValid = errors.length === 0;
Now, we have a consistent interface and can add rules just be adding additional objects to our array!
Creating a Reusable Validation Function
To extend the utility of our validator, we can create a function that takes an object, a set of rules, and returns errors and validation status. Let's create that function.
const validate = (obj, rules) => {
const errors = rules.reduce((errs, rule) => {
const result = rule.test(obj);
if (result === false) {
errs.push(rule.message);
}
return errs;
}, []);
return {
errors,
isValid: errors.length === 0
}
}
Now, we can use this function wherever we need to validate an object! Let's try with our previous example and use a user object that's not quite valid:
// Invalid user object
const user = {
name: "Bob",
password: "kaBob123",
confirmPassword: "kaBob12",
age: 17,
};
// Validation rules
const rules = [
{
test: (user) => user.name.length > 2,
message: "User's name is too short",
},
{
test: (user) => user.password.length >= 8,
message: "User's password is too short",
},
{
test: (user) => user.password === user.confirmPassword,
message: "Password and confirmation do not match",
},
{
test: (user) => user.age >= 18,
message: "User must be at least 18 years old",
},
];
// Validation function
const validate = (obj, rules) => {
const errors = rules.reduce((errs, rule) => {
const result = rule.test(obj);
if (result === false) {
errs.push(rule.message);
}
return errs;
}, []);
return {
errors,
isValid: errors.length === 0,
};
};
// Testing our object
const result = validate(user, rules);
// {
// errors:
// [ 'Password and confirmation do not match',
// 'User must be at least 18 years old' ],
// isValid: false
// }
I hope you enjoyed this exploration of using Array.reduce
to make our object validations just a bit more consistent and enjoyable.
Happy coding!
Top comments (12)
Note: the name and password length validation can be done with HTML alone. No need for JavaScript. See the minlength attribute.
Good point - but i d like to think that this is also for server side validation. My rule of thumb: validate on the frontend for comfort , validate on the server for security .
My thought exactly.
HTML and JavaScript validation can be bypassed easily using the Developer Tools. If you plan on sending any data from the frontend to the server-side, you have to perform layered validation.
With the HTML then the JavaScript and finally the server-side. If they get past the first two, unless there is a hole in the server-side validation they are not getting past that.
Better still use a whitelist and deny any input that is not on this list.
Frontend form validation is not done for security, it's for user experience.
Backend validation is security, ideally frontend validation should be so good that non-malign users will mostly never hit those backend validation errors.
Imho frontend and backend validations serve completely different purposes and cannot directly be compared.
Frontend form validation is a mixture of good user experience with security in mind.
Respectfully, frontend validation has absolutely zero to do with security.
Thanks very clear
I like this one a lot, thanks for sharing Nick!
Platform crossover! 💪
I like this! You should flesh out the idea a bit more and publish an npm package 😃
Excellent example 👍 Thanks