DEV Community

Cover image for Simple and lightweight way to validate javascript object using max-validator
Malkhazi Dartsmelidze
Malkhazi Dartsmelidze

Posted on

Simple and lightweight way to validate javascript object using max-validator

Hello, I hope you have seen my first article about max-validator where I talk about this library and the way to use it.

Today I released max-validator's update and it became more flexible and compatible for almost every requirement. 🥰


First of all lets talk about how install and use max-validator and then I'll introduce you to updates.

Installation is like every other npm package:

npm i max-validator --save
# or
npm install max-validator --save 
# or using yarn
yarn add max-validator

Then you can use it with only one method call:

import V from 'max-validator';
V.validate(data, validationScheme);

Where data is simple javascript object containing data to validate and validationScheme is object where keys are data keys and values are scheme rules.

Let's see example how we can validate user registration form:

var validationScheme = {
  name: 'required|min:3|max:50|alpha',
  lastname: 'required|min:3|max:50|alpha',
  email: 'required|email|ends_with:gmail.com',
  birthdate: 'required|date',
  address: 'required|string|max:100|contains_one:st,str,ave,avenue,#',
  password: 'required|min:6|alpha_num',
  age: 'required|between:18,70|number'
};

var result = V.validate({
  name: 'Malkhazi', 
  lastname: 'Dartsmelidze', 
  email: 'examplemail@gmail.com',
  birthdate: '1997-17-07',
  age: 22,
  address: 'Rustaveli Avenue #333',
  password: '12345678',
  password_confirm: '12345678',
}, validationScheme);

I thought it already was very simple and compact but I realized that I was wrong then I decided to add new features to it and make it very flexible, usable and full validation library, so I did it.

First see minor changes:
In version max-validator@1.1.0 I added and changed a few validation rules:

  • contains_one
  • contains_all
  • numeric
  • alpha_numeric

And now lets talk about Major Changes:

You can pass array of rules in Validation scheme:

V.validate(data, {
  name: ['required', 'min:3', 'max:50', 'alpha'],
  email: ['required', 'email', 'ends_with:gmail.com'],
});

You can pass object of rules in Validation scheme:

V.validate(data, {
  name: {
    required: true,
    min: 3,
    max: 50,
    alpha: true
  },
  email: {
    required: true,
    email: true,
    max: 50,
    ends_with: 'gmail.com'
  }
});

In this way rules are more readable, 🧐 flexible and it has major advantage - Conditional Rules:

V.validate(data, {
  name: ['required', 'min:3', 'max:50', canWriteNickname ? 'alpha_numeric' : 'alpha'],
  email: ['required', 'email', requiredGmailEmail ? 'ends_with:gmail.com' : ''],
});

In max-validator@1.0 we couldn't validate whether email or nickname was unique or address was correct address or not,

But now you can do it with inline or predefined validation functions.
Lets see how it works:

function checkIfEmailIsUnique(value){
  var response = checkEmail(value)
  if(response.isUnique) {
    return true;
  }

  return 'Sorry, this email is already used';
}

V.validate(data, {
  name: ['required', 'min:3', 'max:50', canWriteNickname ? 'alpha_numeric' : 'alpha'],
  email: ['required', 'email', requiredGmailEmail ? 'ends_with:gmail.com' : '', checkIfEmailIsUnique, function(value){
    /* You can pass as many inline functions as you want */
    return 'Just return true if value is valid or return string if you want to get error';
  }],
  nickname: {
    required: true,
    alpha_numeric: true,
    max: 50,
    checkNickname: function(value){
      var response = checkEmail(value)
      if(response.isUnique) {
        return true;
      }

      return 'Nickname not aviable';
    }
  }
});

Pretty interesting, huh? 😍

But what about password confirmation, which is very important input for registration form? 🙄 Or what about whether age is correct relative to birthdate? 🙄
max-validator@1.1.0 - Challenge accepted 😎

Simply pass second argument in function and you get entire validation data:

var result = V.validate({
  name: 'Malkhazi', 
  lastname: 'Dartsmelidze', 
  email: 'examplemail@gmail.com',
  birthdate: '1997-17-07',
  age: 22,
  address: 'Rustaveli Avenue #333',
  password: '12345678',
  password_confirm: '12345678',
}, {
  ...
  password: 'required|min:6|alpha_numeric',
  password_confirm: [
    function(value, data){
      if(value === data.password) return true;

      return 'Passwords didn\'t match'
    }
  ],
  age: {
    required: true,
    between: [18, 70],
    validateIfCorrect: function(value, data){
      if(value != moment().diff(moment(value.date, 'YYYY-MM-DD'), 'years')) {
        return 'Age or birthdate is incorrect';
      }
      return true;
    }
  }
});

max-validator is not even 2.5KB in size which is extremly important in front-end applications.

My next major goals is to integrate it with other libraries like: Formik, react-hook-form and others.

Note: Formik validator Yup is 30KB and react-hook-form's validator joi is 41KB

Oh, I almost forgot to write how to use max-validator with React.js.

Before that, lets learn how to get errors:

var result = Validator.validate(data, validationScheme);

// Get if validate returned error
result.hasError; // Boolean

// Get errors object
result.errors; // Object

// Get if given field has error
result.isError('name'); // Boolean

// Get if given field has error of given validation rule
result.isError('name', 'max'); // Boolean
result.isError('name', 'myCustomFunctionNamePassedInArrayOrObject'); // Boolean
// Note: you cant get whether inline function passed validation or not

// Get first validation error message of field
result.getError('name'); // String

// Get all validation error messages of field
result.getError('name', true); // String (joined messages with comma)

Now use it in React.js:

import React from 'react';
import V from 'max-validate';

const LoginForm = (props) => {
  const [formState, setFormState] = React.useState({
    isValid: false,
    values: {},
    touched: {},
    errors: V.empty(),
  });

  useEffect(() => {
    const result = V.validate(formState.values, {
      email: 'required|email',
      password: 'required|min:6'
    });

    setFormState((formState) => ({...formState,
      isValid: result.hasError,
      errors: result.hasError ? result : V.empty(),
    }));
  }, [formState.values]);

  const handleChange = (event) => {
    event.preventDefault();

    setFormState((formState) => ({ ...formState,
      values: { ...formState.values,
        [event.target.name]: event.target.value,
      },
      touched: {...formState.touched,
        [event.target.name]: true,
      },
    }));
  };

  const hasError =  (field) => (formState.touched[field] && formState.errors.isError(field));

  return (
    <form>
      <input hasError={hasError('email')} name="email" onChange={handleChange} />
      <input hasError={hasError('password')} name="password" onChange={handleChange} />
      <button disabled={!formState.isValid}>Login</button>
    </form>
  );
}

Thank you for reading this article, I hope you liked it.
If so, please Share this article Star and Watch Guthub Repository to get notifications about changes and realeases, this helps me sooooo much.

Top comments (0)