Using Array.Reduce to Streamline Your JavaScript Object Validations

nas5w

Nick Scialli (he/him)

Posted on April 27, 2020

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!

πŸ’– πŸ’ͺ πŸ™… 🚩
nas5w
Nick Scialli (he/him)

Posted on April 27, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related