DEV Community

Cover image for The easy and lightweight way to validate data in React Components & Node.js
Malkhazi Dartsmelidze
Malkhazi Dartsmelidze

Posted on • Updated on

The easy and lightweight way to validate data in React Components & Node.js

👉 Click here to see new update about this package

Hi, I always wanted to write an article on dev.to and this is my first post about my very first package on npm and of course I'm very excited about it.

First of all I'll introduce you myself. I am full stack software engineer with two year experience writing code using PHP, Laravel, Node.js, React.js, Golang and etc.

Today I want to tell you about my package: max-validator

max-validator is very simple, lightweight (only 2.1kb gzipped), and highly customizable solution to validate javascript object and React.js forms as well.


To install max-validator just run following command in your terminal:

$ npm install --save max-validator

Then use it in your Component or node.js request Handler:

import V from 'max-validate';

const examplePerson = {
  name     : 'John',
  lastname : 'Doe',
  birthdate: '1997-07-17',
  age      : 22,
  email    : 'johndoe@gmail.com',
};

const result = V.validate(examplePerson, {
  name     : 'required|string|min:2|max:30',
  lastname : 'required|string|min:2|max:30',
  birthdate: 'required|date',
  age      : 'required|numeric|min:18|max:100',
  email    : 'required|email|max:50',
});

V.validate() function receives only 2 parameters

  • First parameter must be javascript object containing info to validate
  • Second parameter must be correct scheme which validates above data

Validation scheme contains rules with parameters separated by | symbol.

By default max-validator comes with predefined rules:

  • min {age: 'required|min:18' }
  • max {:height: 'required|max:250' }
  • between {age: 'required|between:18,50' }
  • checked {privacy_policy: 'required|checked' }
  • object {info: 'required|object' }
  • array {points: 'required|array' }
  • boolean {isStudent: 'required|boolean' }
  • alpha_numeric {phoneNumber: 'required|alpha_numeric' }
  • alpha {name: 'required|alpha' }
  • email {email: 'required|email' }
  • alpha_dash {slug: 'required|alpha_dash' }
  • in_array {gender: 'required|in_array:male,female' }
  • not_in {status: 'required|not_in:declined' }
  • json {data: 'required|json' }
  • ip {:ipAdress: 'required|ip' }
  • url {:website: 'required|url' }
  • equals {type: 'required|equals:person' }
  • not_equals {currency: 'required|not_equals:eur' }
  • starts_with {certificate: 'required|starts_with:iso_' }
  • ends_with {email: 'required|ends_with:gmail.com' }
  • date {birthdate: 'required|date' }

And 4 additional rules to validate data:

  • required - Returns error if value is not present or is null or empty
  • nullable - Does not returns error if value is empty, undefined, or null
  • string - Passes value into validator as string
  • numeric - Passes value intro validator as number

Here you can see more about rule and its parameters.


To validate data you have to call validate method like this: V.validate(data, scheme) which returns object containing following fields:

  • hasError - Boolean that represents whether validation failed or not
const result = V.validate(data, scheme);
consol.log(result.hasError); // true or false
  • isError - Function that returns if validation failed for specifig field
const result = V.validate(data, scheme);
consol.log(result.isError('name')); // true or false
consol.log(result.isError('name', 'max')); // true or false (To know validator failed for max length reason)
  • getError - Function that returns first or all error message of specifig field
const result = V.validate(data, scheme);
consol.log(result.getError('name')); // name is required
consol.log(result.getError('name', true)); // name is required, name must contain at least 3 characters

It is very simple to extend max-validator and add your own rule as well.
For example you want to check if given value is array and array length is greater than given param:

import V from 'max-validator';

/**
 * You can add as many params as you want or spread params using spread operator ...params
 * @param {string} RuleName
 * @param {function} ValidatorFunction
 * @param {?string} ErrorMessage
 */
V.extend('custom_array', function(value, min_length){
  const err = { min_length: min_length }

  if(Array.isArray(value) && value.length <= min_length ) {
    return true;
  }

  return err;
}, 'array is invalid, it must have at least :min_length elements');
// You can pass value in message as well

Then you can use rule which was created above:

import V from 'max-validator'

const result = V.validate({data: [1, 2, 3, 4] }, {data:'required|array|custom_array:5'});

console.log(result.hasError, result.isError('data'), result.getError('data'));
// true, true, array is invalid, it must have at least 5 elements

Now you know how to extend validator and handle errors as well, isn't it very simple?


You can also simply override default messages too with setMessages method, where object keys are rule names:

import V from 'max-validate';

V.setMessages({
  required: 'value is required',
  min: 'Minimum value for :name is not met'
  ...
});

V.setDefaultMessage('Something is invalid in your data');

As I said above max-validate is compatible with React.js too.
Here is very simple code to validate user login form:

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>
  );
}

If you want to learn more about max-validator you can look at Github repository and feel free to contribute as well.

Thanks a lot for your interest, I hope you enjoyed it

Oldest comments (14)

Collapse
 
alphavader profile image
KB

Very interesting, thanks

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze

Thank you. I am glad you like it

Collapse
 
maxgrafx profile image
maxgrafx • Edited

looks promising, but the URL that NPM is showing does not exist. looks like a typo, max-validaror is the correct url instead of max-validator that NPM shows

Collapse
 
maxgrafx profile image
maxgrafx

ah you fixed it, lightning fast ;)

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze • Edited

Thank you for note. I edited it and it works now. This is correct url

Collapse
 
maxgrafx profile image
maxgrafx

does it play nice with Formik?

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze

I am going to integrate it with 3rd party libraries and Formik is one of them. I'll let you know when it's ready!

Collapse
 
maxgrafx profile image
maxgrafx

would love to see that, i'm using Yup (which is great) but is about 31Kb's when bundled for production

Collapse
 
dullin profile image
Hugo Leblanc

Question about the design:

Why did you use a single string with separators to create your validation scheme? Is it taken from another format? Is it easier to parse than an object instead?

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze

Nice note, Hugo. You got the point. Laravel Framework has similar validation rules, also I think this design makes package more compact and easy to use

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze

Hello again, Hugo. I released new update, which made possible to change design. You can look details here: dev.to/malkhazidartsmelidze/simple...

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze
Collapse
 
crimsonmed profile image
Médéric Burlet

Reminds me of validate.js but in a more compact but less flexible.

Good job on the nice library for compact quick validation

validatejs.org/

Collapse
 
malkhazidartsmelidze profile image
Malkhazi Dartsmelidze

Thank you for feedback. I'll try to make add more flexibility to it while maintaining compactness