Enforcing data validations through readable definitions
enforce
is a data validation tool that allows you to assert rules on supplied variables and parameters, using a human-friendly format.
To install enforce
, run the following code in your npm project.
npm install --save enforce-js
After installing, simply import the module.
import enforce from 'enforce-js';
To enforce
validation on a variable, simply follow the syntax below.
enforce`${{ variable }} as dataType, rule1, rule2, ...`;
// Validate a variable
const message = 'Hello, world!';
enforce`${{ message }} as a string, with 5 to 20 characters`; // ok
NOTE:
enforce
uses double brackets as a shortcut to{ variable: variable }
enforce
supports primitive javascript data types, which by default, are non-nullable. To explictly define a variable to be nullable, use the optional
keyword.
NOTE: Non-nullable in
enforce
means the value can either beundefined
or the specified data type. It cannot be a javascriptnull
object.
- 'a string'
- 'a number'
- 'a boolean'
- 'an array'
- 'an object'
- 'a function'
- 'an optional string'
- 'an optional number'
- 'an optional boolean'
- 'an optional array'
- 'an optional object'
- 'an optional function'
- 'a value'
- 'any value'
Additional rules can help further validate a supplied variable. If the below rules do not meet the requirements of what may be needed, you may use the and matches REGEXP
rule in order to fill the gap, or you can try Extending Rules.
- 'with
MIN
toMAX
characters' (MIN: number, MAX: number) - 'with
MIN
or more characters' (MIN: number) - 'with up to
MAX
characters' (MAX: number) - 'greater than
MIN
' (MIN: number) - 'greater than or equal to
MIN
' (MIN: number) - 'less than
MAX
' (MAX: number) - 'less than or equal to
MAX
' (MAX: number) - 'and matches
REGEXP
' (REGEXP: regular expression)
enforce
also supports validating class-type objects. To validate whether a supplied variable or parameter is an instance of a class, you can directly supply the class as a data type.
class Animal { /* class definition */ }
const dog = new Animal();
enforce`${{ dog }} as an ${{ Animal }}`; // ok
class Dog extends Animal { /* class definition */ }
const corgi = new Dog();
enforce`${{ corgi }} as a ${{ Dog }}`; // ok
enforce`${{ corgi }} as an ${{ Animal }}`; // ok
enforce`${{ dog }} as a ${{ Dog }}`; // error!
By default, if a given parameter does not meet the rules provided, a ValidationError
will be thrown with a message containing the original definition. To better handle the error, an additional name
parameter is also supplied to let you know which parameter was invalid.
const countingNumber = -1;
enforce`${{ countingNumber }} as a number, greater than or equal to 0`;
// OUTPUT
// error.message: 'countingNumber' must be a number, greater than or equal to 0
// error.name: countingNumber
The recommended approach is to have a try-catch block that retrieves the invalid parameter.
import enforce, { ValidationError } from 'enforce-js';
try {
const countingNumber = -1;
enforce`${{ countingNumber }} as a number, greater than or equal to 0`;
}
catch(err) {
if(err instanceof ValidationError) {
console.error(`The error message was: ${err.message}, and the invalid parameter is: ${err.name}`);
}
}
NOTE:
enforce
format is also validated and throws aFormatError
when the supplied definition is invalid.
import enforce, { FormatError } from 'enforce-js';
try {
const countingNumber = -1;
enforce`${{ countingNumber }} as a postive number, and is the square root of 4`;
}
catch(err) {
if(err instanceof FormatError) {
console.error(`The error message was: ${err.message}, and the invalid parameter is: ${err.name}`);
}
}
If you need additional rules currently not supported by enforce
, you can extend the library by using the .extend()
method.
enforce.extend(REGEXP, VALIDATOR);
// REGEXP = Regular Expression matching the rule
// VALIDATOR = Function that will check if the supplied value is valid
// Extend a new rule
enforce.extend(/^and is equal to \d{1,}$/i, (val, rule) => {
// e.g. rule == 'is equal to 5'
const number = parseInt(rule.slice(rule.lastIndexOf(' ')));
return val === number;
});
// Enforce the new rule
const thisNumber = 5;
enforce`${{ thisNumber }} as a number, and is equal to 5`;
// Import module
import enforce, { ValidationError } from 'enforce-js';
// Validate a variable
const message = 'Hello, world!';
enforce`${{ message }} as a string, with 5 to 20 characters`; // ok
// Validate function parameters
const register = ({ username, name, password, age, options }) => {
try {
enforce`${{ username }} as a string`;
enforce`${{ name }} as an optional string`;
enforce`${{ password }} as a string, with 6 to 8 characters`;
enforce`${{ password }} as a password, with 6 to 8 characters, and matches /^\\d{6,8}$/i`;
enforce`${{ age }} as a number, greater than 18`;
enforce`${{ options }} as an optional object`;
const { messages } = options;
enforce`${{ messages }} as a boolean`;
/* function definition */
}
catch(err) {
if(err instanceof ValidationError) {
return `Invalid Parameter: ${err.name}`;
}
}
}
// Use function
const result = register({
username: 'tardisblue', // ok
name: 'Amy Pond', // ok
password: '1234', // error!
age: 21 // ok
});
// result: `Invalid Parameter: password`
// Validate if an object is an instance of a class
class Post { /* class definition */ }
const post = new Post();
enforce`${{ post }} as a ${{ Post }}`; // ok