DEV Community

Cover image for Using Array.Reduce to Streamline Your JavaScript Object Validations
Nick Scialli (he/him)
Nick Scialli (he/him)

Posted on

Using Array.Reduce to Streamline Your JavaScript Object Validations

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
// }
Enter fullscreen mode Exit fullscreen mode

I hope you enjoyed this exploration of using Array.reduce to make our object validations just a bit more consistent and enjoyable.

Happy coding!

Latest comments (12)

Collapse
 
tylerlwsmith profile image
Tyler Smith

I like this one a lot, thanks for sharing Nick!

Collapse
 
nas5w profile image
Nick Scialli (he/him)

Platform crossover! 💪

Collapse
 
chrisbrocklesby profile image
Chris Brocklesby

Excellent example 👍 Thanks

Collapse
 
aleksandrhovhannisyan profile image
Aleksandr Hovhannisyan

Note: the name and password length validation can be done with HTML alone. No need for JavaScript. See the minlength attribute.

Collapse
 
ziizium profile image
Habdul Hazeez • Edited

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.

Collapse
 
spock123 profile image
Lars Rye Jeppesen

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.

Thread Thread
 
ziizium profile image
Habdul Hazeez

Frontend form validation is not done for security, it's for user experience.

Frontend form validation is a mixture of good user experience with security in mind.

Thread Thread
 
spock123 profile image
Lars Rye Jeppesen

Respectfully, frontend validation has absolutely zero to do with security.

Collapse
 
turbopasi profile image
Pascal Lamers

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 .

Collapse
 
ziizium profile image
Habdul Hazeez

My thought exactly.

Collapse
 
joeattardi profile image
Joe Attardi

I like this! You should flesh out the idea a bit more and publish an npm package 😃

Collapse
 
adgower profile image
Alex Gower

Thanks very clear