UNPKG

basic-data-validator

Version:

Basic schema validation JavaScript library (supports Shamsi / Jalaali date)

932 lines (625 loc) 25.9 kB
# Basic-Data-Validator Basic-Data-Validator is a JavaScript library for data validation. At first it was built to be used in **React-Final-Form**, but it is not limited to **_React_** and you can use it in every javascript project. Basic-Data-Validator contains some general Api to create your own **validation schema**. If you want more, you can easily define your `custom` rule. For Persian users it fully supports **Shamsi** (Jalaali) date. Also you can customize all messages or overwrite your message in every rule. ## CONTENT 1. [BasicValidator](#basicvalidator) 2. [Schema Builder](#schema-builder) 3. [API](#api) 4. [Custom Messages](#custom-messages) 5. [EXAMPLES](#examples) ## INSTALL Install via npm: ```sh npm install basic-data-validator ``` Basic-Data-Validator supports Jalaali date validation that uses _Basic-Shamsi_ package. ```sh npm install basic-shamsi ``` ## USAGE Import `BasicValidator` class from the _Basic-Data-Validator_ package. `BasicValidator` accepts an schema (or schema generator) as input argument and validate values. ### Define schema Lets start with an example: ```js import BasicValidator from "basic-data-validator"; const myValidator = BasicValidator((builder) => builder.object({ userName: builder.label("First Name").string().required().userName(), password: builder.string().required().password(), confirmPassword: builder .string() .required() .equals((data) => data.password, "must be equal to password"), address: builder .object({ city: builder.label("CITY").string().required(), postalCode: builder .label("POSTAL CODE") .string() .required() .digits(), }) .required(), }) ); ``` The above schema defines the following constraints: - `userName` - a required string - a valid username: may contains any symboles of \_ – . \ / @ or digits or letters, having a length of 3 to 20 characters - `password` - a required string - requires a password rule: must not contains space and ' symbol, having a length of 3 to 20 characters - `confirmPassword` - a required string - must be equal to value of password field - `address` - a required object - `city` - a required string - `postalCode` - a required string - just contains digits ### Use in Fnal Form You can easily use `myValidator.validate` in **React-Final-Form** . ```jsx <Form onSubmit={onSubmit} validate={myValidator.validate} ... /> ``` Using `validateAll` method enforces all rules to be validated, so you can show all input errors. ```jsx <Form onSubmit={onSubmit} validate={myValidator.validateAll} ... /> ``` ### Use in code Also you can use `myValidator` in your code: ```js const data = { userName: "Mahdi", password: null, confirmPassword: "*" }; const is_valid = myValidator.isValid(data); // false const errors = myValidator.validate(data); /* output: { userName: null, password: 'password is a required field', confirmPassword: 'must be equal to password', address: { city: 'CITY is a required field', postalCode: 'POSTAL CODE is a required field' } } */ ``` Next section will explains more about `BasicValidator` ## BasicValidator `BasicValidator` generates a schema using [schema builder](#schema-builder). ```js const myValidator = BasicValidator(SCHEMA, CUSTOM_MESSAGES); myValidator.isValid(DATA); // returns boolean (true | false) myValidator.vaidate(DATA); // returns first error for each schema class myValidator.vaidateAll(DATA); // returns all errors ``` ### Define schema You can define your own schema using schema builder: ```js const mySchema = builder => builder.object({ userName: builder.string().required().notContains([" ","'"]), password: builder.string().required().notContains([" ","'"]) }) const myValidator = BasicValidator( mySchema ); ... ``` ### Validate values `BasicValidator` returns a validator object with folowing methods: - `isValid(value)`: Returns `true` if the value matches the schema. - `validate(value)` This method match the value and schema. For each schema class it will stop at first error. - `validateAll(value)` This method match the value and schema. It checks all validation rules and extract all errors in each validation schema. ## Schema Builder Helps you to define validation schema. It contains folowing methods: - #### `label( text )` Labels the name of property. Use this method when you are using [validator level](#custom-messages) messages. ```js (builder) => builder.label("User Name"); ``` - #### `string( message )` Generates an instance of `StringSchema` and also adds a rule that will be matched when value is undefined, null or string. ```js (builder) => builder.stirng("JUST STRING VALUE ALLOWED"); ``` - #### `inSensitive()` All string rules are case sensitive. Using this method right before string() method, makes them case in-sensitive. ```js (builder) => builder.inSensitive().stirng(); ``` - #### `number( message )` Generates an instance of `NumberSchema` and also adds a rule that will be matched when value is undefined, null or number. ```js (builder) => builder.number(); ``` - #### `bool( message )` Generates an instance of `BooleanSchema` and also adds a rule that will be matched when value is undefined, null or boolean. ```js (builder) => builder.bool(); ``` - #### `shamsi( message )` Generates an instance of `ShamsiSchema` and also adds a rule that will be matched when value is undefined, null or valid Shamsi (Jalaali) date. ```js (builder) => builder.shamsi(); ``` - #### `object( DEFINED-SCHEMA-OBJECT)` Generates an instance of `ObjectSchema` and also adds a rule that will be matched when value is undefined, null or object. ```js (builder) => builder.object({}); ``` ## API There are 5 classes of schema `StringSchema`, `NumberSchema`, `BooleanSchema`, `ShamsiSchema` and `ObjectSchema` ### StringSchema This schema class contains folowing methods: - #### `custom(fn, message)` Allows you to write your custom match function to validate a string. This function takes 2 argument: the **value** (current evaluation value) and the **data** (current evaluation object) ```js var schema = builder => builder.string() .custom((value, data) => value > data.startDate, "CUSTOM ERROR MESSAGE")); ``` Default vaildation error: DefaultMessages.Invalid - #### `required(message)` Will not allow undefined or null as value. ```js var schema = (builder) => builder.string().required(); ``` Default vaildation error: DefaultMessages.Required - #### `equals(value, message)` Just the specified value is allwed. ```js var schema = (builder) => builder.string().equals("Mahdi"); ``` Late binding: The `value` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = builder => builder.object({ ... confirmPassword: builder.string() .equals(data => data.password) ... }); ``` Default validation error: DefaultMessages.Equals - #### `notEquals(value, message)` The specified value is not allwed. ```js var schema = (builder) => builder.string().notEquals("Mahdi"); ``` Late binding: The `value` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = builder => builder.object({ ... lastName: builder.string() .notEquals(data => data.firstName) ... }); ``` Default validation error: DefaultMessages.NotEquals - #### `email(message)` Requires the string value to be a valid email address. ```js var schema = (builder) => builder.string().email(); ``` Default validation error: DefaultMessages.Email - #### `url(message)` Requires the string value to be a valid url address. ```js var schema = (builder) => builder.string().url(); ``` Default validation error: DefaultMessages.Url - #### `match(regex, message)` Requires the `regex` pattern to match the string value. ```js var schema = (builder) => builder.string().match(/^[0-9]+$/); ``` Late binding: The `regex` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .equals((data) => (data.typeId == 1 ? /^[0-9]+$/ : /^[a-zA-Z]+$/)); ``` Default validation error: DefaultMessages.Matches - #### `userName(message)` Requires the string value to be a valid user name (Contains any symboles of \_ – . \ / @ or digits or letters, having a length of 3 to 20 characters) ```js var schema = (builder) => builder.string().userName(); ``` Default validation error: DefaultMessages.UserName - #### `strongPassword(message)` Requires the string value to be a strong password that has at least one lowercase letter, one uppercase letter, one digit, one special character, and is at least **8** characters long. ```js var schema = (builder) => builder.string().strongPassword(); ``` Default validation error: DefaultMessages.StrongPassword - #### `mediumPassword(message)` Requires the string value to be a medium password that has at least one lowercase letter, one uppercase letter, one digit, one special character, and is at least **6** characters long. ```js var schema = (builder) => builder.string().mediumPassword(); ``` Default validation error: DefaultMessages.MediumPassword - #### `password(message)` Requires the string value to be a valid password that has at 3 and characters and not contains space and ' (single quotation) ```js var schema = (builder) => builder.string().password(); ``` This is a shortcut for `.notContains([" ", "'"]).min(3).max(20)`. - #### `digits(message)` Requires the string value to only contain 0-9. ```js var schema = (builder) => builder.string().digits(); ``` Default validation error: DefaultMessages.Digits - #### `letters(message)` Requires the string value to only contain a-z or A-Z. ```js var schema = (builder) => builder.string().letters(); ``` Default validation error: DefaultMessages.Letters - #### `alphanum(message)` Requires the string value to only contain a-z, A-Z or 0-9. ```js var schema = (builder) => builder.string().alphanum(); ``` Default validation error: DefaultMessages.AlphaNum - #### `min(min, message)` Specifies the minimum length limit for the string value. ```js var schema = (builder) => builder.string().min(3); ``` Late binding: The `min` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string().min((data) => (data.typeId == 1 ? 3 : 10)); ``` Default validation error: DefaultMessages.MinLen - #### `max(max, message)` Specifies the maximum length limit for the string value. ```js var schema = (builder) => builder.string().max(3); ``` Late binding: The `max` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string().max((data) => (data.typeId == 1 ? 3 : 10)); ``` Default validation error: DefaultMessages.MaxLen - #### `length(length, message)` Specifies the length limit for the string value. ```js var schema = (builder) => builder.string().length(3); ``` Late binding: The `length` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string().length((data) => (data.typeId == 1 ? 3 : 10)); ``` Default validation error: DefaultMessages.Length - #### `trim(message)` Requires the string value to be trimmed. ```js var schema = (builder) => builder.string().trim(); ``` Default validation error: DefaultMessages.Trim - #### `lowerCase(lowerCase, message)` Requires the string value to be lowercase. ```js var schema = (builder) => builder.string().lowerCase(); ``` Default validation error: DefaultMessages.LowerCase - #### `upperCase(upperCase, message)` Requires the string value to be uppercase. ```js var schema = (builder) => builder.string().upperCase(); ``` Default validation error: DefaultMessages.UpperCase - #### `contains(values, message)` Requires the string value at least contains one of `values`. ```js var schema = (builder) => builder.string().contains(["US", "UK"]); ``` Late binding: The `values` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .contains((data) => data.typeId == 1 ? ["US", "UK"] : ["RUSSIA", "CHINA"]); ``` Also the items of `values` can be a function. ```js var schema = builder => builder.string() .contains(['US', 'UK', data => data.typeId == 1? 'RUSSIA', 'CHINA']); ``` Default validation error: DefaultMessages.Contains - #### `notContains(values, message)` Requires the string value does not contain any of `values`. ```js var schema = (builder) => builder.string().notContains(["RUSSIA", "CHINA"]); ``` Late binding: The `values` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .notContains((data) => data.typeId == 1 ? ["US", "UK"] : ["RUSSIA", "CHINA"]); ``` Also the items of `values` can be a function. ```js var schema = builder => builder.string() .notContains(['US', 'UK', data => data.typeId == 1? 'RUSSIA', 'CHINA']); ``` Default validation error: DefaultMessages.NotContains - #### `oneOf(values, message)` Requires the string value to be one of `values`. ```js var schema = (builder) => builder.string().oneOf(["RUSSIA", "CHINA"]); ``` Late binding: The `values` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .oneOf((data) => data.typeId == 1 ? ["US", "UK"] : ["RUSSIA", "CHINA"]); ``` Also the items of `values` can be a function. ```js var schema = builder => builder.string() .oneOf(['US', 'UK', data => data.typeId == 1? 'RUSSIA', 'CHINA']); ``` Default validation error: DefaultMessages.OneOf - #### `notOneOf(values, message)` Requires the string value not to be one of `values`. ```js var schema = (builder) => builder.string().notOneOf(["RUSSIA", "CHINA"]); ``` Late binding: The `values` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .notOneOf((data) => data.typeId == 1 ? ["US", "UK"] : ["RUSSIA", "CHINA"]); ``` Also the items of `values` can be a function. ```js var schema = builder => builder.string() .notOneOf(['US', 'UK', data => data.typeId == 1? 'RUSSIA', 'CHINA']); ``` Default validation error: DefaultMessages.NotOneOf ## NumberSchema This class contains folowing methods: - #### `custom(fn, message)` Refer to [`string.custom()`](#customfn-message) - #### `required(message)` Refer to [`string.required()`](#requiredmessage) - #### `equals(value, message)` Refer to [`string.equals()`](#equalsvalue-message) - #### `notEquals(value, message)` Refer to [`string.notEquals()`](#notequalsvalue-message) - #### `integer(message)` Requires the value to be an _integer_ or _null_ or _undefined_ ```js var schema = (builder) => builder.number().integer(); ``` Default validation error: DefaultMessages.Integer - #### `min(min, message)` Set the minimum value allowed. ```js var schema = (builder) => builder.number().min(5); ``` Late binding: The `min` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.number().min((data) => (data.typeId == 1 ? 5 : 10)); ``` Default validation error: DefaultMessages.Min - #### `max(max, message)` Set the maximum value allowed. ```js var schema = (builder) => builder.number().max(15); ``` Late binding: The `max` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.number().max((data) => (data.typeId == 1 ? 15 : 10)); ``` Default validation error: DefaultMessages.Max - #### `lessThan(max, message)` Value must be less than `max`. ```js var schema = (builder) => builder.number().lessThan(15); ``` Late binding: The `max` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.number().lessThan((data) => (data.typeId == 1 ? 15 : 10)); ``` Default validation error: DefaultMessages.LessThan - #### `moreThan(min, message)` Value must be more than `min`. ```js var schema = (builder) => builder.number().moreThan(5); ``` Late binding: The `min` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.number().moreThan((data) => (data.typeId == 1 ? 5 : 10)); ``` Default validation error: DefaultMessages.MoreThan - #### `positive(message)` Value must be positive number. ```js var schema = (builder) => builder.number().positive(); ``` Default validation error: DefaultMessages.Positive - #### `negative(message)` Value must be negative number. ```js var schema = (builder) => builder.number().negative(); ``` Default validation error: DefaultMessages.Negative - #### `oneOf(values, message)` Refer to [`string.oneOf()`](#oneOfvalues-message) - #### `notOneOf(values, message)` Refer to [`string.notOneOf()`](#notOneOfvalues-message) ## BooleanSchema This class contains folowing methods: - #### `custom(fn, message)` Refer to [`string.custom()`](#customfn-message) - #### `required(message)` Refer to [`string.required()`](#requiredmessage) - #### `equals(value, message)` Refer to [`string.equals()`](#equalsvalue-message) - #### `notEquals(value, message)` Refer to [`string.notEquals()`](#notequalsvalue-message) ## ShamsiSchema This class contains folowing methods: - #### `custom(fn, message)` Refer to [`string.custom()`](#customfn-message) - #### `required(message)` Refer to [`string.required()`](#requiredmessage) - #### `equals(value, message)` Refer to [`string.equals()`](#equalsvalue-message) - #### `notEquals(value, message)` Refer to [`string.notEquals()`](#notequalsvalue-message) - #### `min(min, message)` Set the minimum Shamsi date allowed. ```js var schema = (builder) => builder.number().min("1400/01/01"); ``` Late binding: The `min` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder.string() .min((data) => (data.typeId == 1 ? "1400/01/01" : "1400/07/01")); ``` Default validation error: DefaultMessages.MinShamsi - #### `max(max, message)` Set the maximum Shamsi date allowed. ```js var schema = (builder) => builder.number().max("1400/01/01"); ``` Late binding: The `max` argument can be a function, so it will be calculated each time it is accessed. ```js var schema = (builder) => builder .string() .max((data) => (data.typeId == 1 ? "1400/01/01" : "1400/07/01")); ``` Default validation error: DefaultMessages.MaxShamsi ## ObjectSchema This class contains folowing methods: - #### `required(message)` Refer to [`string.required()`](#requiredmessage) ## Custom Messages In `BasicValidator` you can custimize error messages in 2 ways. ### Rule Level In each rule you can optinally define your error message. ```js var schema = (builder) => builder .number("VALUE MUST BE A NUMBER") .required("CAN NOT BE EMPTY") .max(10, "VALUE <= 10"); ``` ### Validator Level Also you can customize all or some of messages in each validator. You can find list of all messages in the file `basic-data-validator/lib/messages.js`. like this: ```js export const DefaultMessages = { Invalid: "{path} is invalid", Required: "{path} is a required field", Equals: "{path} field must be equal to {value}", NotEquals: "{path} field must be not equal to {value}", String: "{path} must be a string", Email: "{path} must be a valid email", Url: "{path} must be a valid URL", Matches: '{path} must match the following: "{regex}"', UserName: "{path} is not a valid user name", StrongPassword: "{path} is not a strong password", MediumPassword: "{path} is not a medium password", Digits: '{path} must contains only numbers"', Letters: '{path} must contains only letters"', AlphaNum: '{path} must contains letters or numbers"', MinLen: "{path} must be at least {min} characters", MaxLen: "{path} must be at most {max} characters", Length: "{path} must be exactly {length} characters", Trim: "{path} must be a trimmed string", LowerCase: "{path} must be a lowercase string", UpperCase: "{path} must be a upper case string", Contains: "{path} must contains one of the following values: {values}", NotContains: "{path} must not contains one of the following values: {values}", OneOf: "{path} must be one of the following values: {values}", NotOneOf: "{path} must not be one of the following values: {values}", Number: "{path} must be a number", Integer: "{path} must be an integer", Min: "{path} must be greater than or equal to {min}", Max: "{path} must be less than or equal to {max}", LessThan: "{path} must be less than {less}", MoreThan: "{path} must be greater than {more}", Positive: "{path} must be a positive number", Negative: "{path} must be a negative number", Boolean: "{path} field must be boolean", Shamsi: "{path} field must be Shamsi date", MinShamsi: "{path} field must be later than {min}", MaxShamsi: "{path} field must be at earlier than {max}", }; ``` Define your new messages and pass it as second argument in `basic-data-validator` ```js const MyValidatorMessages = { Required: "CAN NOT BE EMPTY", Number: "VALUE MUST BE A NUMBER", Max: "VALUE <= {max}", }; var mySchemaBuilder = (builder) => builder.number().required().max(10, "10"); const myValidator = BasicValidator(mySchemaBuilder, MyValidatorMessages); ``` `Basic-Data-Validator` will use default message if you miss to overwrite it. ## EXAMPLES #### Example 1: validate simple value ```js const validator = BasicValidator((b) => b.string().strongPassword()); validator.isValid("do,p!#32Z?"); // true validator.validate("do,p!#32Z?"); // null validator.isValid("123"); // false validator.validate("123"); // ? is not a strong password ``` #### Example 2: password must not contains user name ```js const validator = BasicValidator(b => b.object({ ... userName: b.string().required(), password: b.inSensitive().string().required(), .notContains(d => d.userName, 'password must not contains user name'), ... })); ``` #### Example 3: confirm password must be equal to password ```js const validator = BasicValidator(b => b.object({ ... password: b.string().required(), confirmPassword: b.string().required() .equals(d => d.password, 'must be equal to password'), ... })); ``` #### Example 4: End date must be earlier than start date ```js const validator = BasicValidator(b => b.object({ ... startDate: b.shamsi().required(), endDate: b.shamsi().required() .moreThan(d => d.startDate, 'End date must be earlier than start date'), ... })); ```