body-check v1.0.3
BodyCheck
Overview
This package provides a tool for you to flexibly define cases for validating request body.
This can be especially useful when you need to validate user input in the server or form values in the browser.
This package is inspired by Vue's prop validation.
Support
NodeJS
All Node versions.
Browser
Browser | Version (>=) |
---|---|
Internet Explorer | 11* |
Edge | 12 |
Chrome | 38 |
Firefox | 13 |
Safari | 8 |
Android | 38 |
Opera | 25 |
Firefox for Android | 14 |
* Partial support: Does not support .run
method because it depends on Promise
.
Install
npm install --save body-check
Usage
This package exposes itself using the UMD format.
In module environment:
import BodyCheck from 'body-check';
const checker = new BodyCheck();
In CommonJS environment:
// Requiring the package
const BodyCheck = require('body-check');
const checker = new BodyCheck();
In browser:
<script src="path/to/body-check.js"></script>
<script>
const checker = new BodyCheck();
</script>
Types
The following uses TypeScript declaration syntax to illustrate the types.
CaseName
type CaseName = string | symbol;
BodyCheckConfig
interface BodyCheckConfig {
validator(value: any, ...params: any[]): boolean | string;
error?: string;
params?: any[];
context?: any;
}
BodyCheckCases
interface BodyCheckCases {
[caseName: CaseName]: BodyCheckConfig;
}
BodyCheckResult
interface BodyCheckError {
[caseName: CaseName]: string;
}
BodyCheckValues
interface BodyCheckValues {
[caseName: CaseName]: any;
}
API
The following uses TypeScript declaration syntax to illustrate the types.
Constructor
constructor(cases: BodyCheckCases = {}): this
// Can be created without parameter.
const checker = new BodyCheck();
// Or automatically create cases by passing in a [BodyCheckCases](#bodycheckcases).
const checker = new BodyCheck({
email: {
validator: value => isEmail(value),
error: 'Email is invalid.'
},
confirmPassword: {
validator: (value, password) => value === password,
error: 'Passwords do not matach.',
params: [request.body.password]
}
});
Methods
isObjectLiteral(value: any): boolean
This method is used internally to check if a value is an object literal.
It is exposed publicly tho. So you can use it.
const checker = new BodyCheck();
checker.isObjectLiteral([]);
// -> false
checker.isObjectLiteral(checker);
// -> false
checker.isObjectLiteral({});
// -> true
isValidConfig(value: any): boolean
This method is used internally to check if a value matches the BodyCheckConfig interface.
const checker = new BodyCheck();
checker.isValidConfig([]);
// -> false
checker.isValidConfig({
error: 'some error',
params: [/* some params */],
context: `thisArg`
});
// -> false
checker.isValidConfig({
validator: 'not function'
});
// -> false
checker.isValidConfig({
validator: n => n === 10
});
// -> true
checker.isValidConfig({
validator: n => n === 10,
params: 'not array'
});
// -> false
checker.isValidConfig({
validator: (v, n) => v === n,
params: [10]
});
// -> true
hasCase(name: CaseName): boolean
Check if a case already exists.
const symbol = Symbol('example');
const checker = new BodyCheck({
example: {
validator(){
return this.toString() === 'example'
},
context: 'example'
},
[symbol]: {
validator: n => n === 'symbol'
}
});
checker.hasCase('example');
// -> true
checker.hasCase(symbol);
// -> true
checker.hasCase('any');
// -> false
getCase(name: CaseName): BodyCheckConfig | undefined
Get the configuration object of a case.
const symbol = Symbol('example');
const checker = new BodyCheck({
[symbol]: {
validator: (n, ...i) => i.includes(n),
params: [1, 2, 3]
}
});
checker.getCase('example');
// -> undefined
checker.getCase(symbol);
// -> { validator: [object Function], params: [1, 2, 3] }
addCase(name: CaseName, config: BodyCheckConfig): this
Add new case to the instance.
This method is chainable.
// Add case with constructor
const checker = new BodyCheck({
any: {
validator: n => !n
}
});
// Add case with .addCase method
checker.addCase('example', {
validator(str){
return str === this.toString()
},
context: 'example'
});
// Adding case with the same name will throw an error
checker.addCase('example', {
validator: n => !!n
});
// Exception: TypeError
// Adding case with invalid config will throw an error
checker.addCase('example2', {});
// Exception: TypeError
editCase(name: CaseName, config: object): this
Edit existing cases of the instance.
The method will extend the existing configuration object with the config
parameter. The resulting configuration will be checked using .isValidConfig()
before being updated to the instance.
This method is chainable.
const checker = new BodyCheck({
example: {
validator: (v, n) => v === n
}
});
// If a case is not found, throws error.
checker.editCase('not found', {
params: [10]
});
// Exception: ReferenceError
// If `config` makes the existing configuration invalid, throws error.
checker.editCase('example', {
validator: 'not function'
});
// Exception: TypeError
checker.editCase('example', {
params: [10]
});
// Success
removeCase(name: CaseName): boolean
Remove a case from the instance.
const checker = new BodyCheck({
example: {
validator: n => !!n
}
});
checker.removeCase('example');
// -> true
clear(): void
Clear all cases from the instance.
const checker = new BodyCheck({
example: {
validator: n => !!n
}
});
checker.clear();
run(valueObj: BodyCheckValues): Promise<true | BodyCheckError | TypeError | ReferenceError>
In environment that does not natively support Promise
, you must include a polyfill for Promise
to correctly run this method. Otherwise, exception will be thrown.
Asynchronously run all tests with the values provided.
The test will iterate through the properties in valueObj
. As such, property key that is not found in the instance will throw an exception.
Not all existing cases must be validated, but all valueObj
properties must correspond to an existing case.
Case names that are not found in valueObj
will be skipped when running the validation.
const symbol = Symbol('example');
const checker = new BodyCheck({
defaultError: {
validator: n => n < 10
},
customDefaultError: {
validator: n => n < 10,
error: 'This is wrong!'
},
customError: {
validator: v => v || 'No!'
},
parameters: {
validator: (v, p) => v === p,
params: ['password']
},
this: {
validator: function(n){
return this.valueOf() === n;
},
context: 10
},
[10]: {
validator: v => !!v;
},
[symbol]: {
validator: v => !!v;
}
});
checker.run({
defaultError: 10,
customDefaultError: 10,
customError: false,
parameters: 'password',
this: 10,
10: 1,
[symbol]: 1
}).then(obj => {
/**
* Resolves as an object containing caseName-error pair:
* {
* defaultError: 'Validation for case "defaultError" failed with this value: 10',
* customDefaultError: 'This is wrong!',
* customError: 'No!'
* }
*/
});
runSync(valueObj: BodyCheckValues): true | BodyCheckError
Synchronously run all tests with the values provided.
The test will iterate through the properties in valueObj
. As such, property key that is not found in the instance will throw an exception.
Not all existing cases must be validated, but all valueObj
properties must correspond to an existing case.
Case names that are not found in valueObj
will be skipped when running the validation.
const symbol = Symbol('example');
const checker = new BodyCheck({
defaultError: {
validator: n => n < 10
},
customDefaultError: {
validator: n => n < 10,
error: 'This is wrong!'
},
customError: {
validator: v => v || 'No!'
},
parameters: {
validator: (v, p) => v === p,
params: ['password']
},
this: {
validator: function(n){
return this.valueOf() === n;
},
context: 10
},
[10]: {
validator: v => !!v;
},
[symbol]: {
validator: v => !!v;
}
});
checker.runSync({
defaultError: 10,
customDefaultError: 10,
customError: false,
parameters: 'password',
this: 10,
10: 1,
[symbol]: 1
});
/**
* Returns an object containing caseName-error pair:
* {
* defaultError: 'Validation for case "defaultError" failed with this value: 10',
* customDefaultError: 'This is wrong!',
* customError: 'No!'
* }
*/
Properties
The following uses TypeScript declaration syntax to illustrate the types.
cases: Map<CaseName, BodyCheckConfig>
Returns a Map of all cases with its configuration.
This is used internally. You should not change this value if you don't know what you're doing.
This property is unwritable and unenumerable. To change this value, you need to use Object.defineProperty
to redefine its descriptors.
size: number
Returns the total amount of cases currently in the instance.