Coder Social home page Coder Social logo

fastest-validator's Introduction

Photos from @ikukevk

Node CI Coverage Status Codacy Badge Known Vulnerabilities Size

fastest-validator NPM version Tweet

⚡ The fastest JS validator library for NodeJS | Browser | Deno.

Key features

  • blazing fast! Really!
  • 20+ built-in validators
  • many sanitizations
  • custom validators & aliases
  • nested objects & array handling
  • strict object validation
  • multiple validators
  • customizable error messages
  • programmable error object
  • no dependencies
  • unit tests & 100% coverage

How fast?

Very fast! 8 million validations/sec (on Intel i7-4770K, Node.JS: 12.14.1)

√ validate                            8,678,752 rps

Compared to other popular libraries:

Result

50x faster than Joi.

Would you like to test it?

$ git clone https://github.com/icebob/fastest-validator.git
$ cd fastest-validator
$ npm install
$ npm run bench

Approach

In order to achieve lowest cost/highest performance redaction fastest-validator creates and compiles functions using the Function constructor. It's important to distinguish this from the dangers of a runtime eval, no user input is involved in creating the validation schema that compiles into the function. This is as safe as writing code normally and having it compiled by V8 in the usual way.

Installation

NPM

You can install it via NPM.

$ npm i fastest-validator --save

or

$ yarn add fastest-validator

Usage

Validate

The first step is to compile the schema to a compiled "checker" function. After that, to validate your object, just call this "checker" function.

This method is the fastest.

const Validator = require("fastest-validator");

const v = new Validator();

const schema = {
    id: { type: "number", positive: true, integer: true },
    name: { type: "string", min: 3, max: 255 },
    status: "boolean" // short-hand def
};

const check = v.compile(schema);

console.log("First:", check({ id: 5, name: "John", status: true }));
// Returns: true

console.log("Second:", check({ id: 2, name: "Adam" }));
/* Returns an array with errors:
    [
        {
            type: 'required',
            field: 'status',
            message: 'The \'status\' field is required!'
        }
    ]
*/

Try it on Repl.it

Halting

If you want to halt immediately after the first error:

const v = new Validator({ haltOnFirstError: true });

Browser usage

<script src="https://unpkg.com/fastest-validator"></script>
const v = new FastestValidator();

const schema = {
    id: { type: "number", positive: true, integer: true },
    name: { type: "string", min: 3, max: 255 },
    status: "boolean" // short-hand def
};

const check = v.compile(schema);

console.log(check({ id: 5, name: "John", status: true }));
// Returns: true

Deno usage

With esm.sh, now Typescript is supported

import FastestValidator from "https://esm.sh/fastest-validator@1"

const v = new FastestValidator();
const check = v.compile({
    name: "string",
    age: "number",
});

console.log(check({ name: "Erf", age: 18 })); //true

Supported frameworks

Optional, Required & Nullable fields

Optional

Every field in the schema will be required by default. If you'd like to define optional fields, set optional: true.

const schema = {
    name: { type: "string" }, // required
    age: { type: "number", optional: true }
}

const check = v.compile(schema);

check({ name: "John", age: 42 }); // Valid
check({ name: "John" }); // Valid
check({ age: 42 }); // Fail because name is required

Nullable

If you want disallow undefined value but allow null value, use nullable instead of optional.

const schema = {
    age: { type: "number", nullable: true }
}

const check = v.compile(schema);

check({ age: 42 }); // Valid
check({ age: null }); // Valid
check({ age: undefined }); // Fail because undefined is disallowed
check({}); // Fail because undefined is disallowed

Nullable and default values

null is a valid input for nullable fields that has default value.

const schema = {
   about: { type: "string", nullable: true, default: "Hi! I'm using javascript" }
}

const check = v.compile(schema)

const object1 = { about: undefined }
check(object1) // Valid
object1.about // is "Hi! I'm using javascript"

const object2 = { about: null }
check(object2) // valid
object2.about // is null

check({ about: "Custom" }) // Valid

Considering null as a value

In specific case, you may want to consider null as a valid input even for a required field.

It's useful in cases you want a field to be:

  • required and null without specifying nullable: true in its definition.
  • required and not null by specifying nullable: false in its definition.
  • optional but specifically not null.

To be able to achieve this you'll have to set the considerNullAsAValue validator option to true.

const v = new Validator({considerNullAsAValue: true});

const schema = {foo: {type: "number"}, bar: {type: "number", optional: true, nullable: false}, baz: {type: "number", nullable: false}};
const check = v.compile(schema);

const object1 = {foo: null, baz: 1};
check(object1); // valid (foo is required and can be null)

const object2 = {foo: 3, bar: null, baz: 1};
check(object2); // not valid (bar is optional but can't be null)

const object3 = {foo: 3, baz: null};
check(object3); // not valid (baz is required but can't be null)

With this option set all fields will be considered nullable by default.

Strict validation

Object properties which are not specified on the schema are ignored by default. If you set the $$strict option to true any additional properties will result in an strictObject error.

const schema = {
    name: { type: "string" }, // required
    $$strict: true // no additional properties allowed
}

const check = v.compile(schema);

check({ name: "John" }); // Valid
check({ name: "John", age: 42 }); // Fail

Remove additional fields

To remove the additional fields in the object, set $$strict: "remove".

Multiple validators

It is possible to define more validators for a field. In this case, only one validator needs to succeed for the field to be valid.

const schema = {
    cache: [
        { type: "string" },
        { type: "boolean" }
    ]
}

const check = v.compile(schema);

check({ cache: true }); // Valid
check({ cache: "redis://" }); // Valid
check({ cache: 150 }); // Fail

Root element schema

Basically the validator expects that you want to validate a Javascript object. If you want others, you can define the root level schema, as well. In this case set the $$root: true property.

Example to validate a string variable instead of object

const schema = {
    $$root: true,
    type: "string", 
    min: 3, 
    max: 6
};

const check = v.compile(schema);

check("John"); // Valid
check("Al"); // Fail, too short.

Sanitizations

The library contains several sanitizers. Please note, the sanitizers change the original checked object.

Default values

The most common sanitizer is the default property. With it, you can define a default value for all properties. If the property value is null* or undefined, the validator set the defined default value into the property.

Static Default value example:

const schema = {
    roles: { type: "array", items: "string", default: ["user"] },
    status: { type: "boolean", default: true },
};

const check = v.compile(schema);

const obj = {}

check(obj); // Valid
console.log(obj);
/*
{
    roles: ["user"],
    status: true
}
*/

Dynamic Default value: Also you can use dynamic default value by defining a function that returns a value. For example, in the following code, if createdAt field not defined in object`, the validator sets the current time into the property:

const schema = {
    createdAt: {
        type: "date",
        default: (schema, field, parent, context) => new Date()
    }
};

const check = v.compile(schema);

const obj = {}

check(obj); // Valid
console.log(obj);
/*
{
    createdAt: Date(2020-07-25T13:17:41.052Z)
}
*/

Shorthand definitions

You can use string-based shorthand validation definitions in the schema.

const schema = {
    password: "string|min:6",
    age: "number|optional|integer|positive|min:0|max:99", // additional properties
    state: ["boolean", "number|min:0|max:1"] // multiple types
}

Array of X

const schema = {
    foo: "string[]" // means array of string
}

const check = v.compile(schema);

check({ foo: ["bar"] }) // true

Nested objects

const schema = {
   dot: {
      $$type: "object",
      x: "number",  // object props here
      y: "number",  // object props here
   }, 
   circle: {
      $$type: "object|optional", // using other shorthands
      o: {
         $$type: "object",
         x: "number",
         y: "number",
      },
      r: "number"
   }
};

Alias definition

You can define custom aliases.

v.alias('username', {
    type: 'string',
    min: 4,
    max: 30
    // ...
});

const schema = {
    username: "username|max:100", // Using the 'username' alias
    password: "string|min:6",
}

Default options

You can set default rule options.

const v = new FastestValidator({
    defaults: {
        object: {
            strict: "remove"
        }
    }
});

Label Option

You can use label names in error messages instead of property names.

const schema = {
	email: { type: "email", label: "Email Address" },
};
const check = v.compile(schema);

console.log(check({ email: "notAnEmail" }));

/* Returns
[
  {
    type: 'email',
    message: "The 'Email Address' field must be a valid e-mail.",
    field: 'email',
    actual: 'notAnEmail',
    label: 'Email Address'
  }
]
*/

Built-in validators

any

This does not do type validation. Accepts any types.

const schema = {
    prop: { type: "any" }
}

const check = v.compile(schema)

check({ prop: true }); // Valid
check({ prop: 100 }); // Valid
check({ prop: "John" }); // Valid

array

This is an Array validator.

Simple example with strings:

const schema = {
    roles: { type: "array", items: "string" }
}
const check = v.compile(schema)

check({ roles: ["user"] }); // Valid
check({ roles: [] }); // Valid
check({ roles: "user" }); // Fail

Example with only positive numbers:

const schema = {
    list: { type: "array", min: 2, items: {
        type: "number", positive: true, integer: true
    } }
}
const check = v.compile(schema)

check({ list: [2, 4] }); // Valid
check({ list: [1, 5, 8] }); // Valid
check({ list: [1] }); // Fail (min 2 elements)
check({ list: [1, -7] }); // Fail (negative number)

Example with an object list:

const schema = {
    users: { type: "array", items: {
        type: "object", props: {
            id: { type: "number", positive: true },
            name: { type: "string", empty: false },
            status: "boolean"
        }
    } }
}
const check = v.compile(schema)

check({
    users: [
        { id: 1, name: "John", status: true },
        { id: 2, name: "Jane", status: true },
        { id: 3, name: "Bill", status: false }
    ]
}); // Valid

Example for enum:

const schema = {
    roles: { type: "array", items: "string", enum: [ "user", "admin" ] }
}

const check = v.compile(schema)

check({ roles: ["user"] }); // Valid
check({ roles: ["user", "admin"] }); // Valid
check({ roles: ["guest"] }); // Fail

Example for unique:

const schema = {
    roles: { type: "array", unique: true }
}
const check = v.compile(schema);

check({ roles: ["user"] }); // Valid
check({ roles: [{role:"user"},{role:"admin"},{role:"user"}] }); // Valid
check({ roles: ["user", "admin", "user"] }); // Fail
check({ roles: [1, 2, 1] }); // Fail

Example for convert:

const schema = {
    roles: { type: "array", items: 'string', convert: true }
}
const check = v.compile(schema);

check({ roles: ["user"] }); // Valid
check({ roles: "user" }); // Valid
// After both validation: roles = ["user"]

Properties

Property Default Description
empty true If true, the validator accepts an empty array [].
min null Minimum count of elements.
max null Maximum count of elements.
length null Fix count of elements.
contains null The array must contain this element too.
unique null The array must be unique (array of objects is always unique).
enum null Every element must be an element of the enum array.
items null Schema for array items.
convert null Wrap value into array if different type provided

boolean

This is a Boolean validator.

const schema = {
    status: { type: "boolean" }
}
const check = v.compile(schema);

check({ status: true }); // Valid
check({ status: false }); // Valid
check({ status: 1 }); // Fail
check({ status: "true" }); // Fail

Properties

Property Default Description
convert false if true and the type is not Boolean, it will be converted. 1, "true", "1", "on" will be true. 0, "false", "0", "off" will be false. It's a sanitizer, it will change the value in the original object.

Example for convert:

const schema = {
    status: { type: "boolean", convert: true}
};

const check = v.compile(schema);

check({ status: "true" }); // Valid

class

This is a Class validator to check the value is an instance of a Class.

const schema = {
    rawData: { type: "class", instanceOf: Buffer }
}
const check = v.compile(schema);

check({ rawData: Buffer.from([1, 2, 3]) }); // Valid
check({ rawData: 100 }); // Fail

Properties

Property Default Description
instanceOf null Checked Class.

currency

This is a Currency validator to check if the value is a valid currency string.

const schema = {
    money_amount: { type: "currency", currencySymbol: '$' }
}
const check = v.compile(schema);


check({ money_amount: '$12.99'}); // Valid
check({ money_amount: '$0.99'}); // Valid
check({ money_amount: '$12,345.99'}); // Valid
check({ money_amount: '$123,456.99'}); // Valid

check({ money_amount: '$1234,567.99'}); // Fail
check({ money_amount: '$1,23,456.99'}); // Fail
check({ money_amount: '$12,34.5.99' }); // Fail

Properties

Property Default Description
currencySymbol null The currency symbol expected in string (as prefix).
symbolOptional false Toggle to make the symbol optional in string, although, if present it would only allow the currencySymbol.
thousandSeparator , Thousand place separator character.
decimalSeparator . Decimal place character.
customRegex null Custom regular expression, to validate currency strings (For eg: /[0-9]*/g).

date

This is a Date validator.

const schema = {
    dob: { type: "date" }
}
const check = v.compile(schema);

check({ dob: new Date() }); // Valid
check({ dob: new Date(1488876927958) }); // Valid
check({ dob: 1488876927958 }); // Fail

Properties

Property Default Description
convert false if true and the type is not Date, try to convert with new Date(). It's a sanitizer, it will change the value in the original object.

Example for convert:

const schema = {
    dob: { type: "date", convert: true}
};

const check = v.compile(schema);

check({ dob: 1488876927958 }, ); // Valid

email

This is an e-mail address validator.

const schema = {
    email: { type: "email" }
}
const check = v.compile(schema);


check({ email: "[email protected]" }); // Valid
check({ email: "[email protected]" }); // Valid
check({ email: "abc@gmail" }); // Fail

Properties

Property Default Description
empty false If true, the validator accepts an empty array "".
mode quick Checker method. Can be quick or precise.
normalize false Normalize the e-mail address (trim & lower-case). It's a sanitizer, it will change the value in the original object.
min null Minimum value length.
max null Maximum value length.

enum

This is an enum validator.

const schema = {
    sex: { type: "enum", values: ["male", "female"] }
}
const check = v.compile(schema);


check({ sex: "male" }); // Valid
check({ sex: "female" }); // Valid
check({ sex: "other" }); // Fail

Properties

Property Default Description
values null The valid values.

equal

This is an equal value validator. It checks a value with a static value or with another property.

Example with static value:

const schema = {
    agreeTerms: { type: "equal", value: true, strict: true } // strict means `===`
}
const check = v.compile(schema);

check({ agreeTerms: true }); // Valid
check({ agreeTerms: false }); // Fail

Example with other field:

const schema = {
    password: { type: "string", min: 6 },
    confirmPassword: { type: "equal", field: "password" }
}
const check = v.compile(schema);

check({ password: "123456", confirmPassword: "123456" }); // Valid
check({ password: "123456", confirmPassword: "pass1234" }); // Fail

Properties

Property Default Description
value undefined The expected value. It can be any primitive types.
strict false if true, it uses strict equal === for checking.

forbidden

This validator returns an error if the property exists in the object.

const schema = {
    password: { type: "forbidden" }
}
const check = v.compile(schema);


check({ user: "John" }); // Valid
check({ user: "John", password: "pass1234" }); // Fail

Properties

Property Default Description
remove false If true, the value will be removed in the original object. It's a sanitizer, it will change the value in the original object.

Example for remove:

const schema = {
    user: { type: "string" },
    token: { type: "forbidden", remove: true }
};
const check = v.compile(schema);


const obj = {
    user: "John",
    token: "123456"
}

check(obj); // Valid
console.log(obj);
/*
{
    user: "John",
    token: undefined
}
*/

function

This a Function type validator.

const schema = {
    show: { type: "function" }
}
const check = v.compile(schema);


check({ show: function() {} }); // Valid
check({ show: Date.now }); // Valid
check({ show: "function" }); // Fail

luhn

This is an Luhn validator. Luhn algorithm checksum Credit Card numbers, IMEI numbers, National Provider Identifier numbers and others

const schema = {
    cc: { type: "luhn" }
}
const check = v.compile(schema);

check({ cc: "452373989901198" }); // Valid
check({ cc: 452373989901198 }); // Valid
check({ cc: "4523-739-8990-1198" }); // Valid
check({ cc: "452373989901199" }); // Fail

mac

This is an MAC addresses validator.

const schema = {
    mac: { type: "mac" }
}
const check = v.compile(schema);

check({ mac: "01:C8:95:4B:65:FE" }); // Valid
check({ mac: "01:c8:95:4b:65:fe"); // Valid
check({ mac: "01C8.954B.65FE" }); // Valid
check({ mac: "01c8.954b.65fe"); // Valid
check({ mac: "01-C8-95-4B-65-FE" }); // Valid
check({ mac: "01-c8-95-4b-65-fe" }); // Valid
check({ mac: "01C8954B65FE" }); // Fail

multi

This is a multiple definitions validator.

const schema = {
    status: { type: "multi", rules: [
        { type: "boolean" },
        { type: "number" }
    ], default: true }
}
const check = v.compile(schema);

check({ status: true }); // Valid
check({ status: false }); // Valid
check({ status: 1 }); // Valid
check({ status: 0 }); // Valid
check({ status: "yes" }); // Fail

Shorthand multiple definitions:

const schema = {
    status: [
        "boolean",
        "number"
    ]
}
const check = v.compile(schema);

check({ status: true }); // Valid
check({ status: false }); // Valid
check({ status: 1 }); // Valid
check({ status: 0 }); // Valid
check({ status: "yes" }); // Fail

number

This is a Number validator.

const schema = {
    age: { type: "number" }
}
const check = v.compile(schema);

check({ age: 123 }); // Valid
check({ age: 5.65 }); // Valid
check({ age: "100" }); // Fail

Properties

Property Default Description
min null Minimum value.
max null Maximum value.
equal null Fixed value.
notEqual null Can't be equal to this value.
integer false The value must be a non-decimal value.
positive false The value must be greater than zero.
negative false The value must be less than zero.
convert false if true and the type is not Number, it's converted with Number(). It's a sanitizer, it will change the value in the original object.

object

This is a nested object validator.

const schema = {
    address: { type: "object", strict: true, props: {
        country: { type: "string" },
        city: "string", // short-hand
        zip: "number" // short-hand
    } }
}
const check = v.compile(schema);

check({
    address: {
        country: "Italy",
        city: "Rome",
        zip: 12345
    }
}); // Valid

check({
    address: {
        country: "Italy",
        city: "Rome"
    }
}); // Fail ("The 'address.zip' field is required!")

check({
    address: {
        country: "Italy",
        city: "Rome",
        zip: 12345,
        state: "IT"
    }
}); // Fail ("The 'address.state' is an additional field!")

Properties

Property Default Description
strict false If true any properties which are not defined on the schema will throw an error. If remove all additional properties will be removed from the original object. It's a sanitizer, it will change the original object.
minProps null If set to a number N, will throw an error if the object has fewer than N properties.
maxProps null If set to a number N, will throw an error if the object has more than N properties.
schema = {
    address: { type: "object", strict: "remove", props: {
        country: { type: "string" },
        city: "string", // short-hand
        zip: "number" // short-hand
    } }
}

let obj = {
    address: {
        country: "Italy",
        city: "Rome",
        zip: 12345,
        state: "IT"
    }
};
const check = v.compile(schema);

check(obj); // Valid
console.log(obj);
/*
{
    address: {
        country: "Italy",
        city: "Rome",
        zip: 12345
    }   
}
*/
schema = {
  address: {
    type: "object",
    minProps: 2,
    props: {
      country: { type: "string" },
      city: { type: "string", optional: true },
      zip: { type: "number", optional: true }
    }
  }
}
const check = v.compile(schema);


obj = {
    address: {
        country: "Italy",
        city: "Rome",
        zip: 12345,
        state: "IT"
    }
}

check(obj); // Valid

obj = {
    address: {
        country: "Italy",
    }
}

check(obj); // Fail
// [
//   {
//     type: 'objectMinProps',
//     message: "The object 'address' must contain at least 2 properties.",
//     field: 'address',
//     expected: 2,
//     actual: 1
//   }
// ]

record

This validator allows to check an object with arbitrary keys.

const schema = {
    surnameGroups: {
        type: 'record',
        key: { type: 'string', alpha: true },
        value: { type: 'array', items: 'string' }
    }
};
const check = v.compile(schema);

check({ surnameGroups: { Doe: ['Jane', 'John'], Williams: ['Bill'] } }); // Valid
check({ surnameGroups: { Doe1: ['Jane', 'John'] } }); // Fail
check({ surnameGroups: { Doe: [1, 'Jane'] } }); // Fail

Properties

Property Default Description
key string Key validation rule (It is reasonable to use only the string rule).
value any Value validation rule.

string

This is a String validator.

const schema = {
    name: { type: "string" }
}
const check = v.compile(schema);

check({ name: "John" }); // Valid
check({ name: "" }); // Valid
check({ name: 123 }); // Fail

Properties

Property Default Description
empty true If true, the validator accepts an empty string "".
min null Minimum value length.
max null Maximum value length.
length null Fixed value length.
pattern null Regex pattern.
contains null The value must contain this text.
enum null The value must be an element of the enum array.
alpha null The value must be an alphabetic string.
numeric null The value must be a numeric string.
alphanum null The value must be an alphanumeric string.
alphadash null The value must be an alphabetic string that contains dashes.
hex null The value must be a hex string.
singleLine null The value must be a single line string.
base64 null The value must be a base64 string.
trim null If true, the value will be trimmed. It's a sanitizer, it will change the value in the original object.
trimLeft null If true, the value will be left trimmed. It's a sanitizer, it will change the value in the original object.
trimRight null If true, the value will be right trimmed. It's a sanitizer, it will change the value in the original object.
padStart null If it's a number, the value will be left padded. It's a sanitizer, it will change the value in the original object.
padEnd null If it's a number, the value will be right padded. It's a sanitizer, it will change the value in the original object.
padChar " " The padding character for the padStart and padEnd.
lowercase null If true, the value will be lower-cased. It's a sanitizer, it will change the value in the original object.
uppercase null If true, the value will be upper-cased. It's a sanitizer, it will change the value in the original object.
localeLowercase null If true, the value will be locale lower-cased. It's a sanitizer, it will change the value in the original object.
localeUppercase null If true, the value will be locale upper-cased. It's a sanitizer, it will change the value in the original object.
convert false if true and the type is not a String, it's converted with String(). It's a sanitizer, it will change the value in the original object.

Sanitization example

const schema = {
    username: { type: "string", min: 3, trim: true, lowercase: true}
}
const check = v.compile(schema);

const obj = {
    username: "   Icebob  "
};

check(obj); // Valid
console.log(obj);
/*
{
    username: "icebob"
}
*/

tuple

This validator checks if a value is an Array with the elements order as described by the schema.

Simple example:

const schema = { list: "tuple" };
const check = v.compile(schema);

check({ list: [] }); // Valid
check({ list: [1, 2] }); // Valid
check({ list: ["RON", 100, true] }); // Valid
check({ list: 94 }); // Fail (not an array)

Example with items:

const schema = {
    grade: { type: "tuple", items: ["string", "number"] }
}
const check = v.compile(schema);

check({ grade: ["David", 85] }); // Valid
check({ grade: [85, "David"] }); // Fail (wrong position)
check({ grade: ["Cami"] }); // Fail (require 2 elements)

Example with a more detailed schema:

const schema = {
    location: { type: "tuple", items: [
        "string",
        { type: "tuple", empty: false, items: [
            { type: "number", min: 35, max: 45 },
            { type: "number", min: -75, max: -65 }
        ] }
    ] }
}
const check = v.compile(schema);

check({ location: ['New York', [40.7127281, -74.0060152]] }); // Valid
check({ location: ['New York', [50.0000000, -74.0060152]] }); // Fail
check({ location: ['New York', []] }); // Fail (empty array)

Properties

Property Default Description
empty true If true, the validator accepts an empty array [].
items undefined Exact schema of the value items

url

This is an URL validator.

const schema = {
    url: { type: "url" }
}
const check = v.compile(schema);

check({ url: "http://google.com" }); // Valid
check({ url: "https://github.com/icebob" }); // Valid
check({ url: "www.facebook.com" }); // Fail

Properties

Property Default Description
empty false If true, the validator accepts an empty string "".

uuid

This is an UUID validator.

const schema = {
    uuid: { type: "uuid" }
}
const check = v.compile(schema);

check({ uuid: "00000000-0000-0000-0000-000000000000" }); // Valid Nil UUID
check({ uuid: "10ba038e-48da-487b-96e8-8d3b99b6d18a" }); // Valid UUIDv4
check({ uuid: "9a7b330a-a736-51e5-af7f-feaf819cdc9f" }); // Valid UUIDv5
check({ uuid: "10ba038e-48da-487b-96e8-8d3b99b6d18a", version: 5 }); // Fail

Properties

Property Default Description
version null UUID version in range 0-6. The null disables version checking.

objectID

You can validate BSON/MongoDB ObjectID's

const  { ObjectID } = require("mongodb") // or anywhere else 

const schema = {
    id: {
        type: "objectID",
        ObjectID // passing the ObjectID class
    }  
}
const check = v.compile(schema);

check({ id: "5f082780b00cc7401fb8e8fc" }) // ok
check({ id: new ObjectID() }) // ok
check({ id: "5f082780b00cc7401fb8e8" }) // Error

Pro tip: By using defaults props for objectID rule, No longer needed to pass ObjectID class in validation schema:

const  { ObjectID } = require("mongodb") // or anywhere else 

const v = new Validator({
    defaults: {
        objectID: {
            ObjectID
        }
    }
})

const schema = {
    id: "objectID" 
}

Properties

Property Default Description
convert false If true, the validator converts ObjectID HexString representation to ObjectID instance, if hexString the validator converts to HexString

Custom validator

You can also create your custom validator.

const v = new Validator({
    messages: {
        // Register our new error message text
        evenNumber: "The '{field}' field must be an even number! Actual: {actual}"
    }
});

// Register a custom 'even' validator
v.add("even", function({ schema, messages }, path, context) {
    return {
        source: `
            if (value % 2 != 0)
                ${this.makeError({ type: "evenNumber",  actual: "value", messages })}

            return value;
        `
    };
});

const schema = {
    name: { type: "string", min: 3, max: 255 },
    age: { type: "even" }
};
const check = v.compile(schema);

console.log(check({ name: "John", age: 20 }, schema));
// Returns: true

console.log(check({ name: "John", age: 19 }, schema));
/* Returns an array with errors:
    [{
        type: 'evenNumber',
        expected: null,
        actual: 19,
        field: 'age',
        message: 'The \'age\' field must be an even number! Actual: 19'
    }]
*/

Or you can use the custom type with an inline checker function:

const v = new Validator({
    useNewCustomCheckerFunction: true, // using new version
    messages: {
        // Register our new error message text
        weightMin: "The weight must be greater than {expected}! Actual: {actual}"
    }
});

const schema = {
    name: { type: "string", min: 3, max: 255 },
    weight: {
        type: "custom",
        minWeight: 10,
        check(value, errors, schema) {
            if (value < minWeight) errors.push({ type: "weightMin", expected: schema.minWeight, actual: value });
            if (value > 100) value = 100
            return value
        }
    }
};
const check = v.compile(schema);

console.log(check({ name: "John", weight: 50 }, schema));
// Returns: true

console.log(check({ name: "John", weight: 8 }, schema));
/* Returns an array with errors:
    [{
        type: 'weightMin',
        expected: 10,
        actual: 8,
        field: 'weight',
        message: 'The weight must be greater than 10! Actual: 8'
    }]
*/
const o = { name: "John", weight: 110 }
console.log(check(o, schema));
/* Returns: true
   o.weight is 100
*/

Please note: the custom function must return the value. It means you can also sanitize it.

Custom validation for built-in rules

You can define a custom function in the schema for built-in rules. With it you can extend any built-in rules.

const v = new Validator({
    useNewCustomCheckerFunction: true, // using new version
    messages: {
        // Register our new error message text
        phoneNumber: "The phone number must be started with '+'!"
    }
});

const schema = {
    name: { type: "string", min: 3, max: 255 },
    phone: { type: "string", length: 15, custom: (v, errors) => {
            if (!v.startsWith("+")) errors.push({ type: "phoneNumber" })
            return v.replace(/[^\d+]/g, ""); // Sanitize: remove all special chars except numbers
        }
    }	
};
const check = v.compile(schema);


console.log(check({ name: "John", phone: "+36-70-123-4567" }));
// Returns: true

console.log(check({ name: "John", phone: "36-70-123-4567" }));
/* Returns an array with errors:
    [{
        message: "The phone number must be started with '+'!",
        field: 'phone',
        type: 'phoneNumber'
    }]
*/

Please note: the custom function must return the value. It means you can also sanitize it.

Asynchronous custom validations

You can also use async custom validators. This can be useful if you need to check something in a database or in a remote location. In this case you should use async/await keywords, or return a Promise in the custom validator functions.

This implementation uses async/await keywords. So this feature works only on environments which supports async/await:

  • Chrome > 55
  • Firefox > 52
  • Edge > 15
  • NodeJS > 8.x (or 7.6 with harmony)
  • Deno (all versions)

To enable async mode, you should set $$async: true in the root of your schema.

Example with custom checker function

const v = new Validator({
    useNewCustomCheckerFunction: true, // using new version
    messages: {
        // Register our new error message text
        unique: "The username is already exist"
    }
});

const schema = {
    $$async: true,
    name: { type: "string" },
    username: {
        type: "string",
        min: 2,
        custom: async (v, errors) => {
            // E.g. checking in the DB that the value is unique.
            const res = await DB.checkUsername(v);
            if (!res) 
                errors.push({ type: "unique", actual: value });

            return v;
        }
    }
    // ...
};

const check = v.compile(schema);

const res = await check(user);
console.log("Result:", res);

The compiled check function contains an async property, so you can check if it returns a Promise or not.

const check = v.compile(schema);
console.log("Is async?", check.async);

Meta information for custom validators

You can pass any extra meta information for the custom validators which is available via context.meta.

const schema = {
    name: { type: "string", custom: (value, errors, schema, name, parent, context) => {
        // Access to the meta
        return context.meta.a;
    } },
};
const check = v.compile(schema);

const res = check(obj, {
    // Passes meta information
    meta: { a: "from-meta" }
});

Custom error messages (l10n)

You can set your custom messages in the validator constructor.

const Validator = require("fastest-validator");
const v = new Validator({
    messages: {
        stringMin: "A(z) '{field}' mező túl rövid. Minimum: {expected}, Jelenleg: {actual}",
        stringMax: "A(z) '{field}' mező túl hosszú. Minimum: {expected}, Jelenleg: {actual}"
    }
});

const schema = {
    name: { type: "string", min: 6 }
}
const check = v.compile(schema);

check({ name: "John" });
/* Returns:
[
    {
        type: 'stringMin',
        expected: 6,
        actual: 4,
        field: 'name',
        message: 'A(z) \'name\' mező túl rövid. Minimum: 6, Jelenleg: 4'
    }
]
*/

Personalised Messages

Sometimes the standard messages are too generic. You can customize messages per validation type per field:

const Validator = require("fastest-validator");
const v = new Validator();
const schema = {
    firstname: {
        type: "string",
        min: 6,
        messages: {
            string: "Please check your firstname",
            stringMin: "Your firstname is too short"
        }
    },
    lastname: {
        type: "string",
        min: 6,
        messages: {
            string: "Please check your lastname",
            stringMin: "Your lastname is too short"
        }
    }
}
const check = v.compile(schema);

check({ firstname: "John", lastname: 23 });
/* Returns:
[
    {
        type: 'stringMin',
        expected: 6,
        actual: 4,
        field: 'firstname',
        message: 'Your firstname is too short'
    },
    {
        type: 'string',
        expected: undefined,
        actual: undefined,
        field: 'lastname',
        message: 'Please check your lastname'
    }
]
*/

Plugins

You can apply plugins:

// Plugin Side
function myPlugin(validator){
    // you can modify validator here
    // e.g.: validator.add(...)
}

// Validator Side
const v = new Validator();
v.plugin(myPlugin)

Message types

Name Default text
required The '{field}' field is required.
string The '{field}' field must be a string.
stringEmpty The '{field}' field must not be empty.
stringMin The '{field}' field length must be greater than or equal to {expected} characters long.
stringMax The '{field}' field length must be less than or equal to {expected} characters long.
stringLength The '{field}' field length must be {expected} characters long.
stringPattern The '{field}' field fails to match the required pattern.
stringContains The '{field}' field must contain the '{expected}' text.
stringEnum The '{field}' field does not match any of the allowed values.
stringNumeric The '{field}' field must be a numeric string.
stringAlpha The '{field}' field must be an alphabetic string.
stringAlphanum The '{field}' field must be an alphanumeric string.
stringAlphadash The '{field}' field must be an alphadash string.
stringHex The '{field}' field must be a hex string.
stringSingleLine The '{field}' field must be a single line string.
stringBase64 The '{field}' field must be a base64 string.
number The '{field}' field must be a number.
numberMin The '{field}' field must be greater than or equal to {expected}.
numberMax The '{field}' field must be less than or equal to {expected}.
numberEqual The '{field}' field must be equal to {expected}.
numberNotEqual The '{field}' field can't be equal to {expected}.
numberInteger The '{field}' field must be an integer.
numberPositive The '{field}' field must be a positive number.
numberNegative The '{field}' field must be a negative number.
array The '{field}' field must be an array.
arrayEmpty The '{field}' field must not be an empty array.
arrayMin The '{field}' field must contain at least {expected} items.
arrayMax The '{field}' field must contain less than or equal to {expected} items.
arrayLength The '{field}' field must contain {expected} items.
arrayContains The '{field}' field must contain the '{expected}' item.
arrayUnique The '{actual}' value in '{field}' field does not unique the '{expected}' values.
arrayEnum The '{actual}' value in '{field}' field does not match any of the '{expected}' values.
tuple The '{field}' field must be an array.
tupleEmpty The '{field}' field must not be an empty array.
tupleLength The '{field}' field must contain {expected} items.
boolean The '{field}' field must be a boolean.
function The '{field}' field must be a function.
date The '{field}' field must be a Date.
dateMin The '{field}' field must be greater than or equal to {expected}.
dateMax The '{field}' field must be less than or equal to {expected}.
forbidden The '{field}' field is forbidden.
email The '{field}' field must be a valid e-mail.
emailEmpty The '{field}' field must not be empty.
emailMin The '{field}' field length must be greater than or equal to {expected} characters long.
emailMax The '{field}' field length must be less than or equal to {expected} characters long.
url The '{field}' field must be a valid URL.
enumValue The '{field}' field value '{expected}' does not match any of the allowed values.
equalValue The '{field}' field value must be equal to '{expected}'.
equalField The '{field}' field value must be equal to '{expected}' field value.
object The '{field}' must be an Object.
objectStrict The object '{field}' contains forbidden keys: '{actual}'.
objectMinProps "The object '{field}' must contain at least {expected} properties.
objectMaxProps "The object '{field}' must contain {expected} properties at most.
uuid The '{field}' field must be a valid UUID.
uuidVersion The '{field}' field must be a valid UUID version provided.
mac The '{field}' field must be a valid MAC address.
luhn The '{field}' field must be a valid checksum luhn.

Message fields

Name Description
field The field name
expected The expected value
actual The actual value

Pass custom metas

In some case, you will need to do something with the validation schema . Like reusing the validator to pass custom settings, you can use properties starting with $$

const check = v.compile({
    $$name: 'Person',
    $$description: 'write a description about this schema',
    firstName: { type: "string" },
    lastName: { type: "string" },
    birthDate: { type: "date" }    
});

Development

npm run dev

Test

npm test

Coverage report

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |      100 |    97.73 |      100 |      100 |                   |
 lib             |      100 |      100 |      100 |      100 |                   |
  messages.js    |      100 |      100 |      100 |      100 |                   |
  validator.js   |      100 |      100 |      100 |      100 |                   |
 lib/helpers     |      100 |      100 |      100 |      100 |                   |
  deep-extend.js |      100 |      100 |      100 |      100 |                   |
  flatten.js     |      100 |      100 |      100 |      100 |                   |
 lib/rules       |      100 |    96.43 |      100 |      100 |                   |
  any.js         |      100 |      100 |      100 |      100 |                   |
  array.js       |      100 |      100 |      100 |      100 |                   |
  boolean.js     |      100 |      100 |      100 |      100 |                   |
  custom.js      |      100 |       50 |      100 |      100 |                 6 |
  date.js        |      100 |      100 |      100 |      100 |                   |
  email.js       |      100 |      100 |      100 |      100 |                   |
  enum.js        |      100 |       50 |      100 |      100 |                 6 |
  equal.js       |      100 |      100 |      100 |      100 |                   |
  forbidden.js   |      100 |      100 |      100 |      100 |                   |
  function.js    |      100 |      100 |      100 |      100 |                   |
  luhn.js        |      100 |      100 |      100 |      100 |                   |
  mac.js         |      100 |      100 |      100 |      100 |                   |
  multi.js       |      100 |      100 |      100 |      100 |                   |
  number.js      |      100 |      100 |      100 |      100 |                   |
  object.js      |      100 |      100 |      100 |      100 |                   |
  string.js      |      100 |    95.83 |      100 |      100 |             55,63 |
  tuple.js       |      100 |      100 |      100 |      100 |                   |
  url.js         |      100 |      100 |      100 |      100 |                   |
  uuid.js        |      100 |      100 |      100 |      100 |                   |
-----------------|----------|----------|----------|----------|-------------------|

Contribution

Please send pull requests improving the usage and fixing bugs, improving documentation and providing better examples, or providing some tests, because these things are important.

License

fastest-validator is available under the MIT license.

Contact

Copyright (C) 2019 Icebob

@icebob @icebob

fastest-validator's People

Contributors

0x0a0d avatar akazakou avatar alexjab avatar andersnm avatar andersonjoseph avatar anri-asaturov avatar avanelli avatar balbaal avatar darky avatar erfanium avatar eyalpost avatar ffkl avatar franzzemen avatar freezystem avatar gamote avatar hugebdu avatar icebob avatar intech avatar ishan-srivastava avatar ispyinternet avatar mbaertschi avatar ngraef avatar ninerian avatar rhzs avatar shawnmcknight avatar thib3113 avatar tiagomestreteixeira avatar tinchoz49 avatar veirt avatar victal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fastest-validator's Issues

Not compatible with JSON-schema draft 4

Hello,

It's compared with ajv then i tried to make it work on a side project and i discover it's not compatible with JSON schema.

My question is what is the point to compare the speed of two different things ? ajv and djv works with JSON schema draft 4 & 6 but not fastest-validator.

Do you plan to support the JSON schema draft ?
If not, can we have a disclaimer about this point to avoid mistake ?

Typedefs are broken

Typedefs are so broken, guys, please consider disabling them until sensible PR is made.

some examples:

  • missing 'empty'
  • 'items' can be an object

I'm sure I will find more if i continue looking at api.

Thank You 💌📭

Hey @icebob,

Just wanted to share my thanks for this project. I've finally had time to integrate it into an existing backend and it's been a joy.

In addition to the its performance, I believe it to have the clearest & best API all-around.

I've unfortunately not been following the project's history, so this thank-you extends to the team members and maintainers who I've not tagged, of course 🙏

That is all~!

Optional if another field has been filled

Is it possible to set optional or not according to the completion of another schema field? I just need to say whether the field is required or not depending on the other, not to perform a custom validation. Example:

const schema = {
	type: { type: "enum", values: ['A', 'B'] },
	field_a: {
		type: "string",
		min: 3,
		optional(schema) {
			return (schema.type !== 'A');
		}
	}
};

Property '$$strict' of type 'boolean | undefined' is not assignable to...

node_modules/fastest-validator/index.d.ts:548:3 - error TS2411: Property '$$strict' of type 'boolean | undefined' is not assignable to string index type 'string | boolean | RuleAny | RuleCustom | RuleArray<any> | RuleBoolean | RuleDate | RuleEmail | RuleEnum<any> | RuleForbidden | RuleFunction | RuleLuhn | RuleMac | ... 6 more ... | ValidationRuleObject[]'.

548     $$strict?: boolean;

Little hack resolved the issue for me by adding undefined type to interface ValidationSchema.

Numeric string validator.

I was using the validator and I noticed that I can't validate numeric strings. I was trying with:

const v = new Validator;

const schema = {
  price: {type: 'number', convert: true}
}

const uno = {
  price: '100.30'
}

const dos = {
  price: '10x0.30'
}

const tres = {
  price: 's'
}

const cuatro = {
  price: ''
}

console.log(v.validate(uno, schema)); // true
console.log(v.validate(dos, schema)); // error
console.log(v.validate(tres, schema)); // error
console.log(v.validate(cuatro, schema)); // true :(

So I made a 'numeric String' rule using a regExp /^-?[0-9]\d*(\.\d+)?$/

const schema = {
  price: {type: 'string', numeric: true}
}

const uno = {
  price: '123'
}

const dos = {
  price: '12.30'
}

const tres = {
  price: ''
}

const cuatro = {
  price: '12x'
}

console.log(v.validate(uno, schema)); // true
console.log(v.validate(dos, schema)); // true

console.log(v.validate(tres, schema)); // error {type: stringNumeric, message: 'The field price must be a numeric string,
                                       // expected: A numeric string, actual: ''}

console.log(v.validate(cuatro, schema)); // error {type: stringNumeric, message: 'The field price must be a numeric string', 
                                         // expected: A numeric string, actual: '12x'}

What do you think? If it can merge it I can write tests and make a PR.

reserved keywords

is type a reserved keyword? how ho I validate a prop called type without interfering with fastest-validator?

Add sanitizers function

Sanitizers

  • convert strings to numbers
    age: { type: "number", convert: true }
  • convert strings & numbers to booleans
    age: { type: "boolean", convert: true }
  • convert strings to dates
    age: { type: "date", convert: true }
  • trim strings
    name: { type: "string", trim: true }
  • left-trim strings
    name: { type: "string", ltrim: true }
  • right-trim strings
    name: { type: "string", rtrim: true }
  • lowercase strings
    name: { type: "string", lowercase: true }
  • uppercase strings
    name: { type: "string", uppercase: true }
  • normalize emails (lowercase, ...)
    name: { type: "email", normalize: true }
  • default value (if undefined)
    role: { type: "string", optional: true, default: "user" }

Add confirm password validator

something just like this :

var v = new FastestValidator();
let schema = {
    password: { type: "password", confirmed: true }, // required
}

v.validate({ password: "123456", confirm-password: "123456" }, schema); // Valid
v.validate({ password: "123456", confirm-password: "1234567" }, schema); // Fail
v.validate({ password: "123456" }, schema); // Fail

i18n ?

Should we predefine i18n messages for all langs , and specify language when doing

const v = new Validator(language)

?

Incorrect typescript type definition

index.ts

import  Validator from "fastest-validator";

let v = new Validator();

ts-node index.ts

let v = new Validator();
        ^
TypeError: fastest_validator_1.default is not a constructor
    at Object.<anonymous> (/tmp/test/index.ts:3:9)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Module.m._compile (/home/sigoden/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:439:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/sigoden/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/index.ts:442:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at Object.<anonymous> (/home/sigoden/.nvm/versions/node/v10.15.1/lib/node_modules/ts-node/src/bin.ts:154:12)

Feature: Add display name for fields

Currently this is the message shown:
The 'firstName' field length must be greater than or equal to 4 characters long!

We could define a display field to be printed in the message field so it looks better

{
    firstName: {type: "string", min: 4, max: 16, display: 'First Name'},
}

The 'First Name' field length must be greater than or equal to 4 characters long!

Are you ok with the concept? I could send a PR if you dont mind.

`Access denied` whenever I am trying to push to this repository.

Hi,

I was trying to add a new feature to this project but I am getting a Access denied whenever I am trying to push to this repository.
I forked the repo, created a new branch, wrote the code, wrote test cases.
Is there something else that I need to do?

Custom validator ignore personalised message

Hi ✋
I try to use fastest-validator in my projects, but have one major problem at the edge of using custom validators and personalised messages:

const Validator = require("fastest-validator");
const v = new Validator();
const check = v.compile({
  email: { type: "email" },
  password: {
    type: "custom",
    messages: {
      pswdPersonalizedMsg: "Password personalized message!"
    },
    check(value, schema) {
      return value !== "123"
        ? this.makeError("pswdPersonalizedMsg", "123", value)
        : true;
    }
  }
});

console.log("valid", check({ email: "[email protected]", password: "" }));

then a get message: undefined:

0: Object
  type: "pswdPersonalizedMsg"
  expected: "123"
  actual: ""
  field: "password"
  message: undefined

But expect message: "Password personalized message!". See codesandbox.

It seems related to #57

Benchmarks

Hey,

I took a quick look at your library and I thought the results for ajv (which I currently use) seemed a bit off. so I made my own script to do a rough benchmark and it yielded very different results, am I missing something? Do you have the script you used to benchmark ajv?

const Ajv = require('ajv')
const ajv = new Ajv()
const Validator = require("fastest-validator")
const validator = new Validator()

const schemaAjv = {
  type: 'object',
  properties: {
    id: { type: 'string' },
    uset: { items: {
      type: 'object',
      properties: {
        id: { type: 'string' },
        uenum: { items: { type: 'string', enum: ['a', 'b', 'c', 'd'] } }
      }
    } }
  }
}


const schemaFv = {
  id: { type: 'string' },
  uset: { type: 'array', items: {
    type: 'object',
    props: {
      id: { type: 'string' },
      uenum: { type: 'array', items: { type: 'string', enum: ['a', 'b', 'c', 'd'] } }
    }
  } }
}

const data = {
  id: 'aaa',
  uset: [
    {
      id: 'foo',
      uenum: ['b']
    }
  ]
}

const validateAjv = ajv.compile(schemaAjv)
const validateFv = validator.compile(schemaFv)

const tsAjv = Date.now()
for (let i = 1; i <= 10000000; i++) {
  validateAjv(data)
}
console.log('ajv', Date.now() - tsAjv)

const tsFv = Date.now()
for (let i = 1; i <= 10000000; i++) {
  validateFv(data)
}
console.log('fv', Date.now() - tsFv)

Support custom validator

Hello, is possible to use custom validators?
example, I need to use other npm package to validate barcodes. I could use this or any other validator with this package?

const schema = {
    id: { type: "custom", handler:(data)=>{
//return or Promise.resolve() is ok and 
//throw or Promise.reject() to catch errors
}},
};

Add simple enum validator (that can be any of type)

Hi! Thanks for your great tool)
I think "enum" validator will be very userful. At this time this is available for string validator. But, for example, I often use numeric enums in REST API as parameters.
I know that it can be made by using multiple validators. But that will be great to write like:

let schema = {
    status: { type: "enum", values: [null, 1, 2, "done"] }
}
v.validate({ status: "done" }, schema)

自定义实例默认的message时候,参数替换占位无法去除

const messages = {
  default: "参数校验失败!",
  required: "%s参数是必须的!",
  enum: "参数不在指定枚举列表,请检查",
  whitespace: "%s参数不能为空",
  date: {
    format: "%s 日期格式不符合规范",
    parse: "%s 日期格式解析失败, %s 是无效的 ",
    invalid: "%s 日期是无效的"
  },
  types: {
    string: "%s 不是字符类型",
    method: "%s 不是方法类型",
    array: "%s 不是数组",
    object: "%s 不是对象格式",
    number: "%s 不是数字",
    date: "%s 不是日期格式",
    boolean: "%s 不是布尔类型",
    integer: "%s 不是整数",
    float: "%s 不是浮点数",
    regexp: "%s 不符合标准正则表达式",
    email: "%s不符合邮箱格式",
    url: "%s 不符合URL格式",
    hex: "%s 不符合16进制格式"
  },
  string: {
    len: "%s 长度必须是 %s ",
    min: "%s 最小长度是 %s ",
    max: "%s 长度不能超过 %s ",
    range: "%s 长度必须在 %s 和 %s 之间"
  },
  number: {
    len: "%s 必须等于 %s",
    min: "%s 不能小于 %s",
    max: "%s 不能超过 %s",
    range: "%s 值必须在 %s 和 %s之间"
  },
  array: {
    len: "%s 长度必须等于 %s ",
    min: "%s 最小长度是 %s",
    max: "%s 最大长度是 %s",
    range: "%s长度必须在 %s 和 %s 之间"
  },
  pattern: {
    mismatch: "%s 不符合检验格式"
  },
  clone() {
    const cloned = JSON.parse(JSON.stringify(this));
    cloned.clone = this.clone;
    return cloned;
  }
};

const instance = new validator(schema);
      instance
      .validate(data, {
        messages: messages 
      })
      .catch(({ errors, fields }) => {

        if (errors) {
          this.throw(400, _.get(errors, "0.message"));
        }
      });

When validation failed , the method format in util.js,it will replacing the %s %d %j params ,

in my definition, the field of types in messages Object,

I just write one param %s, I think it just replaced only one params ,not appending the rest of args , as https://github.com/yiminghe/async-validator/blob/master/src/util.js#L64

after validation , it actually returns both DataFieldName and SchemaTypeName
I think it makes people confusing 。can you write a note in the README.md? thanks.

[references]
https://github.com/yiminghe/async-validator/blob/master/src/index.js#L171
https://github.com/yiminghe/async-validator/blob/master/src/util.js#L63

Recursive schema

Hi, trying to validate a recursive schema for f.ex a category tree, but errors during v.compile with "Maximum call stack size exceeded".

describe("Test recursive schema", () => {
	const v = new Validator();

	let schema = {};
	Object.assign(schema, {
		name: { type: "string" },
		subcategories: {
			type: "array",
			optional: true,
			items: { type: "object", props: schema}
		}
	});

	let check = v.compile(schema);

	it("should compile", () => {
		let category = {
			name: "top",
			subcategories: [
				{
					name: "sub1"
				},
				{
					name: "sub2"
				}
			]
		};

		let res = check(category);

		expect(res).toBe(true);
	});
});

$strict

Strict flag. If set, throw error if found not defined properties.

Example

let schema = {
    $strict: true,
    name: { type: "string" }
}

v.validate({
    name: "John"
}, schema);
// Valid

v.validate({
    name: "John",
    age: 30,
}, schema);
// Error because 'age' property is not allowed.

Optional parameter "trim"

It would be great if there is similar parameter to "strict" called "trim" which will trim all properties that are not defined by schema.

Is it doable?

Typescript support

This library is great, I love it!, the only thing I'm really missing is Typescript types, if they can be in the repo, like in ajv, even better.

I may be able to work on this in the future if this ends up being my validator of choice.

Either or conditions

I have an API which takes in two input: userId and email
Is there a way to check if either of them is present or not?

Develop in ESM?

Hey,

I was thinking – this library could really benefit from developing with ESM. It's small enough to be used in the browser, but can also be cheaply inlined into servers. Load & parse times get quicker, too.

Very little has to change! ...especially since the codebase is already so neatly organized.

The only draw back is that it involves a build step before publishing, which I used to be against, but it's served me well since adopting the practice for Node.js modules & especially with browser-and-Node.js compatible modules.

The final build would be a single file (one for ESM and one for CJS) that exports the Validator class. You also need to add a module entry to package.json and that's it~!quicker.

Multiple validators + optional = false negative

> (new (require('fastest-validator'))).validate({}, {
    a: [
        { type: 'number', optional: true },
        { type: 'string', optional: true },
    ]
})
[ { type: 'required',
    expected: undefined,
    actual: undefined,
    field: 'a',
    message: 'The \'a\' field is required!' } ]

I expected a not to be considered required.

Email rule allows undefined

Passing undefined to a compiled schema with type: 'email' will not return an error.

Since there isn't an accompanying empty option, I would expect email to require a value. I would also be happy with an empty option so that the rule behaves closer to string.


I can open a separate issue, but the same applies to the built-in url rule.

Thanks!

Simple array validation produces duplicated error

Hey 👋

Not sure if this is expected, but a simple array validation test gives duplicated error. Here is example:

const Validator = require('fastest-validator')

const v = new Validator()

const rules = {
  users: {
    type: 'array',
    items: {
      type: 'object',
      props: {
        name: { type: 'string', 'min': 2 }
      }
    }
  }
}

const data = {
  username: 'a'
}

console.log(v.validate(data, rules))

Actual

The error is that users field is not present, but the error is duplicated:

[ { type: 'required',
    expected: undefined,
    actual: undefined,
    field: 'users',
    message: 'The \'users\' field is required!' },
  { type: 'required',
    expected: undefined,
    actual: undefined,
    field: 'users',
    message: 'The \'users\' field is required!' } ]

Expected

Since there is only one error, this is what I would expect:

[ { type: 'required',
    expected: undefined,
    actual: undefined,
    field: 'users',
    message: 'The \'users\' field is required!' } ]

Versions

fastest-validator 0.6.10
node 10.11.0

Multiple validators - All conditions to true

Hello

I am using fastest-validator in one of my major nodejs project and I was wondering if its possible to make the "Multiple validators" return true only if ALL the conditions are true. Currently it checks if any one condition is true and returns true if so.

Thanks for the wonderful library.

T&R
Soubhik

optional field - prevent null or undefined

Can we have a prop on the fields that tells the validator to treat null or undefined as values that need to be tested?

I want a string field to optional, but if it's specified, it must be a string and cannot be null or undefined. I was thinking of maybe using a custom validator, but it seems my validator never gets called if the input is null.

$ref another schema

I wasn't able to find in the doc a clear reference example.
Like the jsonschema feature: $ref: '#ext' // references another schema

What's the equivalent in fastest-validator?

This is what I'm trying to achieve:

// Example Schema
const ExampleSchema = {
    things: {
      'type': 'array',
      'enum': [
          FirstSchema,
          SecondSchema,
          ThirdSchema,
        ],
      'min': 1,
      }
}

// Other schemas
const FirstSchema = {
    name: 'string',
    host: { type: 'string', min: 1},
    port: { type: 'number', min: 1, integer: true, max: 65535 },
    auth: { type: 'object',
      props: {
        username: { type: 'string' },
        password: { type: 'string' }
      }
    }
}

// ...

[Next] TODO list for the next major version (1.x.x)

Fully rewritten codebase

  • Entire codebase will be rewritten. Compiler will make the source code of the check function and compile it with new Function.

New equal type

  • It checks the value equal (==) to a static value or another property. The strict property uses === to check values.
{
    password: { type: "string", min: 6 },
    confirmPassword: { type: "equal", field: "password", strict: true } // strict means `===`
}
{
    agreeTerms: { type: "equal", value: true }
}

Enhanced shorthand types

  • Using rule properties in string shorthand definition.
{
    password: "string|min:6" // additional properties
    age: "number|optional|integer|positive|min:0|max:99", // additional properties

    retry: ["number|integer|min:0", "boolean"] // multiple types
}

Compile async validator

  • It compiles an async validator function which returns a Promise. On the other hand, it adds a new customAsync custom rule.
const check = validator.compileAsync({
    username: { type: "customAsync", async check(value) { /* .... */} }
});

check(obj).then(res => {
    // Sanitized obj
}).catch(errors => {
    console.log(errors);
});

Sanitizations

Some common sanitization features. It modifies the original object!

  • convert strings to numbers
    age: { type: "number", convert: true }
  • convert strings & numbers to booleans
    age: { type: "boolean", convert: true }
  • convert strings to dates
    age: { type: "date", convert: true }
  • trim strings
    name: { type: "string", trim: true }
  • left-trim strings
    name: { type: "string", trimLeft: true }
  • right-trim strings
    name: { type: "string", trimRight: true }
  • lowercase strings
    name: { type: "string", lowercase: true }
  • uppercase strings
    name: { type: "string", uppercase: true }
  • locale lowercase strings
    name: { type: "string", localeLowercase: true }
  • locale uppercase strings
    name: { type: "string", localeUppercase: true }
  • normalize emails (lowercase, ...)
    name: { type: "email", normalize: true }
  • left padding
    name: { type: "string", padStart: 5, padChar: " " }
  • right padding
    name: { type: "string", padEnd: 5, padChar: "0" }
  • convert (date, number, boolean) to string
    name: { type: "string", convert: true }
  • default value (if undefined or null)
    role: { type: "string", optional: true, default: "user" }
  • remove forbidden properties if remove: true
  • remove extra properties if strict: "remove"

Require full object or nothing

Hey,
I have a validation as follows:

      location: { type: 'object', optional: true, props: {
        longitude: { type: 'number' },
        latitude: { type: 'number' },
      } },

It should pass in two cases:

  1. { location: { longitude: someNumber, latitude: someNumber } }
  2. { }

Right now for second case it will throw error, thinking location.longitute and location.latitude are required.

Type: boolean, equal: true not working

I need to validate if an boolean field is true:

const schema: ValidationSchema = {
    agree: {type: "boolean", equal: true}
}
const obj = {
   agree: false
}

v.validate(obj, schema)

result -> true

Am I doing something wrong?

EDIT: seems like there is no 'equal' or 'nonEqual' check in boolean rule

v0.6.11 broke some specific schemas

I use UUID literals nested keys in validation schema its work on 0.6.10 and was broken in 0.6.11.
Simple example code:

const schema = {
  minPrice: {
    type: 'object',
    props: {
      value: { type: 'number', positive: true, integer: true },
      enabled: 'boolean',
      regions: {
        type: 'object',
        optional: true,
        props: { '12345678-ef85-4c62-b8f3-e00fbbc155d4': { type: 'number', positive: true, integer: true, optional: true } },
      },
    },
  },
};

/**
 * Next line throws
 * SyntaxError: Invalid or unexpected token
 * at new Function (<anonymous>)
 * at Validator.compileSchemaObject (node_modules\fastest-validator\lib\validator.js:114:33)
 * at Validator.compileSchemaRule (node_modules\fastest-validator\lib\validator.js:154:24)
 * at Validator.compileSchemaType (ec-order\node_modules\fastest-validator\dist\index.js:472:15)
 *
 * Generated code looks like
 * propertyPath = (path !== undefined ? path + ".12345678-ef85-4c62-b8f3-e00fbbc155d4" : "12345678-ef85-4c62-b8f3-e00fbbc155d4");
 * res = this.checkSchemaRule(value.12345678-ef85-4c62-b8f3-e00fbbc155d4, compiledObject[0].compiledType, propertyPath, value);
 * if (res !== true) {             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *  this.handleResult(errors, propertyPath, res);
 * }
 */
const result = v.validate(data, schema);

At the moment, I don't have enough time to make a pull request.

Is async custom vlidation supported?

For example checking uniqueness of username from db.
v.validate(toValidate, schema).then().catch(validationErrors);

and using Promise for writing custom validation rule.

Problems with npm

I am using moleculer and found that I can use numeric: true in string validation. I tried and it didnt work. I investigated that there is version 0.6.12 in my node_modules folder (it is written in package.json). But version it not like in gihub 0.6.12 release. Actually I looked through history of file rules/string.js and found that there is https://github.com/icebob/fastest-validator/blob/f20da30ba886c2856cc40de2c5ed01ed72a36f0d/lib/rules/string.js
It is weird that version bump doesnt happen since november of 2018. Very strange.

Multiple validators not working with objects

It seems like multiple validators are not working properly when they are objects.
Here is an example:

const field = {
    type: 'object',
    props: {
        type: {
            type: 'string',
            pattern: /^field$/
        },
        fieldId: {type: 'number', positive: true, integer: true},
        title: {type: 'string', min: 4, max: 50, optional: true},
        values: {
            type: 'array',
            items: {type: 'string', min: 1, max: 50}
        }
    }
};

const seperator = {
    type: 'object',
    props: {
        type: {
            type: 'string',
            pattern: /^seperator$/
        }
    }
};

const col = {
    type: "array",
    min: 1,
    max: 4,
    items: [
        field,
        seperator
    ],
};

const schema = {bla: col};
console.log(validator.validate({bla:[{"type": "sfdf"}]}, schema));

I expect this validation to fail, but it succeeds. It seems like it only checks whether the array contains an object, but does no further validation regarding the properties.

With other types than objects it is working properly, example:

const col = {
    type: "array",
    min: 1,
    max: 4,
    items: [
        {type: 'boolean'},
        {type: 'string', min: 5}
    ],
};

const schema = {bla: col};
console.log(validator.validate({bla:["sfdf"]}, schema));

Fails as expected because the string is to short.

And for a single validator, everything is working fine, too:

const col = {
    type: "array",
    min: 1,
    max: 4,
    items: field
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.