Convert Figma logo to code with AI

yiminghe logoasync-validator

validate form asynchronous

8,886
764
8,886
162

Top Related Projects

11,356

📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3

22,814

Dead simple Object schema validation

33,503

TypeScript-first schema validation with static type inference

20,860

The most powerful data validation library for JS

A simple and composable way to validate data in JavaScript (and TypeScript).

33,863

Build forms in React, without the tears 😭

Quick Overview

async-validator is a powerful and flexible validation library for JavaScript and TypeScript. It provides asynchronous and synchronous validation capabilities for complex objects, making it ideal for form validation in web applications and data validation in various JavaScript environments.

Pros

  • Supports both synchronous and asynchronous validation
  • Highly customizable with a wide range of built-in validators
  • TypeScript support for improved type safety and developer experience
  • Lightweight and has no external dependencies

Cons

  • Learning curve for complex validation scenarios
  • Documentation could be more comprehensive, especially for advanced use cases
  • Limited built-in localization support (requires manual implementation)

Code Examples

  1. Basic object validation:
import Schema from 'async-validator';

const descriptor = {
  name: {
    type: 'string',
    required: true,
    validator: (rule, value) => value.length > 3,
  },
  age: {
    type: 'number',
    min: 18,
    max: 99,
  },
};

const validator = new Schema(descriptor);

validator.validate({ name: 'John', age: 30 }, (errors, fields) => {
  if (errors) {
    // Validation failed
    console.log(errors);
  } else {
    // Validation passed
    console.log('Valid!');
  }
});
  1. Asynchronous validation:
import Schema from 'async-validator';

const descriptor = {
  email: {
    type: 'string',
    required: true,
    validator: (rule, value) => {
      return new Promise((resolve, reject) => {
        checkEmailUniqueness(value, (isUnique) => {
          if (isUnique) {
            resolve();
          } else {
            reject('Email already exists');
          }
        });
      });
    },
  },
};

const validator = new Schema(descriptor);

validator.validate({ email: 'test@example.com' }, (errors, fields) => {
  if (errors) {
    console.log(errors);
  } else {
    console.log('Valid!');
  }
});
  1. Custom error messages:
import Schema from 'async-validator';

const descriptor = {
  username: {
    type: 'string',
    required: true,
    pattern: /^[a-zA-Z0-9_]+$/,
    message: {
      required: 'Username is required',
      pattern: 'Username can only contain letters, numbers, and underscores',
    },
  },
};

const validator = new Schema(descriptor);

validator.validate({ username: 'user@name' }, (errors, fields) => {
  if (errors) {
    console.log(errors[0].message);
  } else {
    console.log('Valid!');
  }
});

Getting Started

  1. Install the package:

    npm install async-validator
    
  2. Import and use in your project:

    import Schema from 'async-validator';
    
    const descriptor = {
      // Define your validation rules here
    };
    
    const validator = new Schema(descriptor);
    
    validator.validate(data, (errors, fields) => {
      if (errors) {
        // Handle validation errors
      } else {
        // Proceed with valid data
      }
    });
    

Competitor Comparisons

11,356

📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3

Pros of Formily

  • More comprehensive form solution with advanced features like dynamic fields and complex layouts
  • Better integration with React and other UI frameworks
  • Extensive documentation and examples for various use cases

Cons of Formily

  • Steeper learning curve due to its complexity and extensive API
  • Heavier package size compared to async-validator
  • May be overkill for simple form validation scenarios

Code Comparison

async-validator:

const descriptor = {
  name: { type: 'string', required: true },
  age: { type: 'number', min: 18 }
};
const validator = new Schema(descriptor);
validator.validate({ name: 'John', age: 16 }, (errors, fields) => {
  if (errors) {
    // Validation failed
  }
});

Formily:

import { createForm } from '@formily/core'
import { Field } from '@formily/react'

const form = createForm()
<Field
  name="name"
  required
  component="Input"
/>
<Field
  name="age"
  required
  validator={{ minimum: 18 }}
  component="NumberPicker"
/>

Summary

async-validator is a lightweight, focused library for form validation, while Formily is a more comprehensive form solution with advanced features. async-validator is simpler to use for basic validation tasks, but Formily offers more power and flexibility for complex form scenarios, especially in React applications.

22,814

Dead simple Object schema validation

Pros of yup

  • More extensive and flexible schema definition capabilities
  • Better TypeScript support with strong type inference
  • Supports asynchronous validation out of the box

Cons of yup

  • Larger bundle size compared to async-validator
  • Steeper learning curve due to more complex API

Code Comparison

yup

import * as Yup from 'yup';

const schema = Yup.object().shape({
  name: Yup.string().required(),
  age: Yup.number().positive().integer().required(),
});

async-validator

import Schema from 'async-validator';

const descriptor = {
  name: { type: 'string', required: true },
  age: { type: 'number', required: true, min: 0, integer: true },
};
const validator = new Schema(descriptor);

Both libraries allow for schema definition and validation, but yup offers a more fluent API and built-in TypeScript support. async-validator has a simpler API but may require additional setup for complex validations. yup's schema definition is more readable and expressive, while async-validator's approach is more concise but potentially less intuitive for complex schemas.

33,503

TypeScript-first schema validation with static type inference

Pros of Zod

  • TypeScript-first approach with strong type inference
  • More extensive validation capabilities, including complex object shapes
  • Better integration with modern TypeScript ecosystems

Cons of Zod

  • Steeper learning curve for developers new to TypeScript
  • Larger bundle size, which may impact performance in some applications

Code Comparison

Async-validator:

const descriptor = {
  name: { type: 'string', required: true },
  age: { type: 'number', min: 18 }
};

Zod:

const schema = z.object({
  name: z.string(),
  age: z.number().min(18)
});

Both libraries offer schema-based validation, but Zod's TypeScript-first approach provides stronger type inference and more complex validation capabilities. Async-validator has a simpler API and may be easier for beginners to pick up, especially in JavaScript-only projects. Zod excels in TypeScript environments and offers more advanced features, but comes with a steeper learning curve and larger bundle size. The choice between the two depends on the project's specific needs, the development team's expertise, and the importance of TypeScript integration.

20,860

The most powerful data validation library for JS

Pros of Joi

  • More comprehensive and feature-rich validation library
  • Supports a wider range of data types and validation scenarios
  • Better documentation and community support

Cons of Joi

  • Larger bundle size, which may impact performance in browser environments
  • Steeper learning curve due to its extensive API and features

Code Comparison

async-validator:

const descriptor = {
  name: { type: 'string', required: true },
  age: { type: 'number', min: 18 }
};
const validator = new Schema(descriptor);
validator.validate({ name: 'John', age: 20 }, (errors, fields) => {
  if (errors) {
    // Validation failed
  }
});

Joi:

const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().min(18)
});
const { error, value } = schema.validate({ name: 'John', age: 20 });
if (error) {
  // Validation failed
}

Both libraries offer similar functionality for basic validation scenarios. async-validator uses a descriptor object to define validation rules, while Joi uses a more fluent API. Joi provides more advanced features and flexibility, but async-validator is simpler and more lightweight for basic use cases.

A simple and composable way to validate data in JavaScript (and TypeScript).

Pros of Superstruct

  • Offers a more flexible and extensible type system with custom types and coercion
  • Provides better TypeScript integration and type inference
  • Supports both synchronous and asynchronous validation

Cons of Superstruct

  • Has a steeper learning curve due to its more complex API
  • May be overkill for simple validation scenarios
  • Lacks some built-in validators that Async-validator provides out of the box

Code Comparison

Async-validator:

const descriptor = {
  name: { type: 'string', required: true },
  age: { type: 'number', min: 18 }
};
const validator = new Schema(descriptor);
validator.validate({ name: 'John', age: 20 }, (errors, fields) => {
  if (errors) {
    // Validation failed
  }
});

Superstruct:

const User = object({
  name: string(),
  age: number().min(18)
});
try {
  const user = create({ name: 'John', age: 20 }, User);
  // Validation passed
} catch (error) {
  // Validation failed
}

Both libraries offer robust validation capabilities, but Superstruct provides a more powerful type system and better TypeScript integration. Async-validator has a simpler API and may be easier to use for basic validation tasks. The choice between them depends on the specific requirements of your project and your preference for API style.

33,863

Build forms in React, without the tears 😭

Pros of Formik

  • More comprehensive form management solution, handling state, validation, and submission
  • Integrates well with React ecosystem and popular UI libraries
  • Extensive documentation and large community support

Cons of Formik

  • Steeper learning curve due to its comprehensive nature
  • Potentially overkill for simple form scenarios
  • Larger bundle size compared to lightweight validators

Code Comparison

Formik:

import { Formik, Form, Field } from 'formik';

<Formik
  initialValues={{ email: '' }}
  validate={values => {
    // Custom validation logic
  }}
  onSubmit={(values, { setSubmitting }) => {
    // Submit logic
  }}
>
  {({ isSubmitting }) => (
    <Form>
      <Field type="email" name="email" />
      <button type="submit" disabled={isSubmitting}>Submit</button>
    </Form>
  )}
</Formik>

Async-validator:

import Schema from 'async-validator';

const descriptor = {
  email: [
    { required: true, message: 'Email is required' },
    { type: 'email', message: 'Invalid email format' }
  ]
};

const validator = new Schema(descriptor);

validator.validate({ email: 'test@example.com' }, (errors, fields) => {
  if (errors) {
    // Handle validation errors
  }
});

Summary

Formik offers a more comprehensive form management solution with React integration, while Async-validator focuses solely on validation. Formik is better suited for complex forms in React applications, whereas Async-validator is lightweight and can be used in various JavaScript environments for simple validation tasks.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

async-validator

NPM version build status Test coverage node version npm download npm bundle size (minified + gzip)

Validate form asynchronous. A variation of https://github.com/freeformsystems/async-validate

Install

npm i async-validator

Usage

Basic usage involves defining a descriptor, assigning it to a schema and passing the object to be validated and a callback function to the validate method of the schema:

import Schema from 'async-validator';
const descriptor = {
  name: {
    type: 'string',
    required: true,
    validator: (rule, value) => value === 'muji',
  },
  age: {
    type: 'number',
    asyncValidator: (rule, value) => {
      return new Promise((resolve, reject) => {
        if (value < 18) {
          reject('too young');  // reject with error message
        } else {
          resolve();
        }
      });
    },
  },
};
const validator = new Schema(descriptor);
validator.validate({ name: 'muji' }, (errors, fields) => {
  if (errors) {
    // validation failed, errors is an array of all errors
    // fields is an object keyed by field name with an array of
    // errors per field
    return handleErrors(errors, fields);
  }
  // validation passed
});

// PROMISE USAGE
validator.validate({ name: 'muji', age: 16 }).then(() => {
  // validation passed or without error message
}).catch(({ errors, fields }) => {
  return handleErrors(errors, fields);
});

API

Validate

function(source, [options], callback): Promise
  • source: The object to validate (required).
  • options: An object describing processing options for the validation (optional).
  • callback: A callback function to invoke when validation completes (optional).

The method will return a Promise object like:

  • then(),validation passed
  • catch({ errors, fields }),validation failed, errors is an array of all errors, fields is an object keyed by field name with an array of errors per field

Options

  • suppressWarning: Boolean, whether to suppress internal warning about invalid value.

  • first: Boolean, Invoke callback when the first validation rule generates an error, no more validation rules are processed. If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.

  • firstFields: Boolean|String[], Invoke callback when the first validation rule of the specified field generates an error, no more validation rules of the same field are processed. true means all fields.

Rules

Rules may be functions that perform validation.

function(rule, value, callback, source, options)
  • rule: The validation rule in the source descriptor that corresponds to the field name being validated. It is always assigned a field property with the name of the field being validated.
  • value: The value of the source object property being validated.
  • callback: A callback function to invoke once validation is complete. It expects to be passed an array of Error instances to indicate validation failure. If the check is synchronous, you can directly return a false or Error or Error Array.
  • source: The source object that was passed to the validate method.
  • options: Additional options.
  • options.messages: The object containing validation error messages, will be deep merged with defaultMessages.

The options passed to validate or asyncValidate are passed on to the validation functions so that you may reference transient data (such as model references) in validation functions. However, some option names are reserved; if you use these properties of the options object they are overwritten. The reserved properties are messages, exception and error.

import Schema from 'async-validator';
const descriptor = {
  name(rule, value, callback, source, options) {
    const errors = [];
    if (!/^[a-z0-9]+$/.test(value)) {
      errors.push(new Error(
        util.format('%s must be lowercase alphanumeric characters', rule.field),
      ));
    }
    return errors;
  },
};
const validator = new Schema(descriptor);
validator.validate({ name: 'Firstname' }, (errors, fields) => {
  if (errors) {
    return handleErrors(errors, fields);
  }
  // validation passed
});

It is often useful to test against multiple validation rules for a single field, to do so make the rule an array of objects, for example:

const descriptor = {
  email: [
    { type: 'string', required: true, pattern: Schema.pattern.email },
    { 
      validator(rule, value, callback, source, options) {
        const errors = [];
        // test if email address already exists in a database
        // and add a validation error to the errors array if it does
        return errors;
      },
    },
  ],
};

Type

Indicates the type of validator to use. Recognised type values are:

  • string: Must be of type string. This is the default type.
  • number: Must be of type number.
  • boolean: Must be of type boolean.
  • method: Must be of type function.
  • regexp: Must be an instance of RegExp or a string that does not generate an exception when creating a new RegExp.
  • integer: Must be of type number and an integer.
  • float: Must be of type number and a floating point number.
  • array: Must be an array as determined by Array.isArray.
  • object: Must be of type object and not Array.isArray.
  • enum: Value must exist in the enum.
  • date: Value must be valid as determined by Date
  • url: Must be of type url.
  • hex: Must be of type hex.
  • email: Must be of type email.
  • any: Can be any type.

Required

The required rule property indicates that the field must exist on the source object being validated.

Pattern

The pattern rule property indicates a regular expression that the value must match to pass validation.

Range

A range is defined using the min and max properties. For string and array types comparison is performed against the length, for number types the number must not be less than min nor greater than max.

Length

To validate an exact length of a field specify the len property. For string and array types comparison is performed on the length property, for the number type this property indicates an exact match for the number, ie, it may only be strictly equal to len.

If the len property is combined with the min and max range properties, len takes precedence.

Enumerable

Since version 3.0.0 if you want to validate the values 0 or false inside enum types, you have to include them explicitly.

To validate a value from a list of possible values use the enum type with a enum property listing the valid values for the field, for example:

const descriptor = {
  role: { type: 'enum', enum: ['admin', 'user', 'guest'] },
};

Whitespace

It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a whitespace property to a rule with a value of true. The rule must be a string type.

You may wish to sanitize user input instead of testing for whitespace, see transform for an example that would allow you to strip whitespace.

Deep Rules

If you need to validate deep object properties you may do so for validation rules that are of the object or array type by assigning nested rules to a fields property of the rule.

const descriptor = {
  address: {
    type: 'object',
    required: true,
    fields: {
      street: { type: 'string', required: true },
      city: { type: 'string', required: true },
      zip: { type: 'string', required: true, len: 8, message: 'invalid zip' },
    },
  },
  name: { type: 'string', required: true },
};
const validator = new Schema(descriptor);
validator.validate({ address: {} }, (errors, fields) => {
  // errors for address.street, address.city, address.zip
});

Note that if you do not specify the required property on the parent rule it is perfectly valid for the field not to be declared on the source object and the deep validation rules will not be executed as there is nothing to validate against.

Deep rule validation creates a schema for the nested rules so you can also specify the options passed to the schema.validate() method.

const descriptor = {
  address: {
    type: 'object',
    required: true,
    options: { first: true },
    fields: {
      street: { type: 'string', required: true },
      city: { type: 'string', required: true },
      zip: { type: 'string', required: true, len: 8, message: 'invalid zip' },
    },
  },
  name: { type: 'string', required: true },
};
const validator = new Schema(descriptor);

validator.validate({ address: {} })
  .catch(({ errors, fields }) => {
    // now only errors for street and name    
  });

The parent rule is also validated so if you have a set of rules such as:

const descriptor = {
  roles: {
    type: 'array',
    required: true,
    len: 3,
    fields: {
      0: { type: 'string', required: true },
      1: { type: 'string', required: true },
      2: { type: 'string', required: true },
    },
  },
};

And supply a source object of { roles: ['admin', 'user'] } then two errors will be created. One for the array length mismatch and one for the missing required array entry at index 2.

defaultField

The defaultField property can be used with the array or object type for validating all values of the container. It may be an object or array containing validation rules. For example:

const descriptor = {
  urls: {
    type: 'array',
    required: true,
    defaultField: { type: 'url' },
  },
};

Note that defaultField is expanded to fields, see deep rules.

Transform

Sometimes it is necessary to transform a value before validation, possibly to coerce the value or to sanitize it in some way. To do this add a transform function to the validation rule. The property is transformed prior to validation and returned as promise result or callback result when pass validation.

import Schema from 'async-validator';
const descriptor = {
  name: {
    type: 'string',
    required: true,
    pattern: /^[a-z]+$/,
    transform(value) {
      return value.trim();
    },
  },
};
const validator = new Schema(descriptor);
const source = { name: ' user  ' };

validator.validate(source)
  .then((data) => assert.equal(data.name, 'user'));

validator.validate(source,(errors, data)=>{
  assert.equal(data.name, 'user'));
});

Without the transform function validation would fail due to the pattern not matching as the input contains leading and trailing whitespace, but by adding the transform function validation passes and the field value is sanitized at the same time.

Messages

Depending upon your application requirements, you may need i18n support or you may prefer different validation error messages.

The easiest way to achieve this is to assign a message to a rule:

{ name: { type: 'string', required: true, message: 'Name is required' } }

Message can be any type, such as jsx format.

{ name: { type: 'string', required: true, message: '<b>Name is required</b>' } }

Message can also be a function, e.g. if you use vue-i18n:

{ name: { type: 'string', required: true, message: () => this.$t( 'name is required' ) } }

Potentially you may require the same schema validation rules for different languages, in which case duplicating the schema rules for each language does not make sense.

In this scenario you could just provide your own messages for the language and assign it to the schema:

import Schema from 'async-validator';
const cn = {
  required: '%s 必填',
};
const descriptor = { name: { type: 'string', required: true } };
const validator = new Schema(descriptor);
// deep merge with defaultMessages
validator.messages(cn);
...

If you are defining your own validation functions it is better practice to assign the message strings to a messages object and then access the messages via the options.messages property within the validation function.

asyncValidator

You can customize the asynchronous validation function for the specified field:

const fields = {
  asyncField: {
    asyncValidator(rule, value, callback) {
      ajax({
        url: 'xx',
        value: value,
      }).then(function(data) {
        callback();
      }, function(error) {
        callback(new Error(error));
      });
    },
  },

  promiseField: {
    asyncValidator(rule, value) {
      return ajax({
        url: 'xx',
        value: value,
      });
    },
  },
};

validator

You can custom validate function for specified field:

const fields = {
  field: {
    validator(rule, value, callback) {
      return value === 'test';
    },
    message: 'Value is not equal to "test".',
  },

  field2: {
    validator(rule, value, callback) {
      return new Error(`${value} is not equal to 'test'.`);
    },
  },
 
  arrField: {
    validator(rule, value) {
      return [
        new Error('Message 1'),
        new Error('Message 2'),
      ];
    },
  },
};

FAQ

How to avoid global warning

import Schema from 'async-validator';
Schema.warning = function(){};

or

globalThis.ASYNC_VALIDATOR_NO_WARNING = 1;

How to check if it is true

Use enum type passing true as option.

{
  type: 'enum',
  enum: [true],
  message: '',
}

Test Case

npm test

Coverage

npm run coverage

Open coverage/ dir

License

Everything is MIT.

NPM DownloadsLast 30 Days