- Provide an easy validation layers building api.
- Support sync & async validation as one.
- Provide a custom (sync & async) validation method registry, for global app usage.
- Support a reduction of a validation stack to an express/connect middleware.
- Support typescript from the box.
- Provide OR relation in the validation stack.
- No dependencies.
// validation-registry.ts
import { CustomRegistryContext } from 'guardian/core/custom-registry';
CustomRegistryContext.registerCustomFunction(
'start-with-X',
function(name: string) {
const prefix = this.args[0]; // dynamically bound context
return name.startsWith(prefix);
}
)
import { Guardian } from 'guardian'
import { NotNull, NotUndefined, Gt, RunCustom } from 'guardian/core/layer-operators';
// instantiate an Guardian object to build the validation layers on top.
const guardian = new Guardian();
// stacking up the layers
guardian.on({
path: ['data.address', 'name'],
errorMessage: 'name & address are required'
}).add([
NotNull(),
NotUndefined()
]);
guardian.on({
path: 'name',
errorMessage: 'name must start with B'
}).add([
RunCustom('start-with-X', 'B')
]);
guardian.on({
path: 'data.list[$]',
errorMessage: 'all items in list are required',
each: true
}).add([
NotNull()
]);
guardian.on({
path: 'data.items[-1].num',
errorMessage: 'last item must be greater than 5',
}).add([
Gt(5)
]);
// compile the target object
guardian.compile({
name: 'Bob',
data: {
address: 'home',
list: [2, null],
items: [
{num: 2},
{num: null},
{num: 6},
{num: 8},
{num: 10}]
}
});
// exec the validations
guardian.run().then(errors => {
console.log(errors);
});
// Output :
[
{
"message": "name & address are required",
"target": null,
"path": "data.address",
"layerKey": 1
},
{
"message": "all items in list are required",
"target": [
2,
null
],
"path": "data.list[$]",
"layerKey": 3
}
]
guardian.stackSummary()
// Output :
┌─────────┬───────┬───────────────────────────────┬────────────────────────────┬─────┐
│ (index) │ Layer │ Name │ Path │ Key │
├─────────┼───────┼───────────────────────────────┼────────────────────────────┼─────┤
│ 0 │ 1 │ [ 'NotNull', 'NotUndefined' ] │ [ 'data.address', 'name' ] │ 1 │
│ 1 │ 2 │ [ 'start-with-X' ] │ 'name' │ 2 │
│ 2 │ 3 │ [ 'NotNull' ] │ 'data.list[$]' │ 3 │
│ 3 │ 4 │ [ 'Gt' ] │ 'data.items[-1].num' │ 4 │
└─────────┴───────┴───────────────────────────────┴────────────────────────────┴─────┘
By using a Guardian object a stack of validation layers can be built to validate a single object target.
const guardian = new Guardian()
on(options: GuardianOptions): LayerAttacher;
on(path: Array<string>): LayerAttacher;
on(path: string): LayerAttacher;
A factory method for LayerAttacher object, with on
method you're setting the configuration for the validation layer you're about to create.
- Example :
guardian.on({
path: 'data.list[$]',
errorMessage: 'all items in list are required',
each: true
}).add([
NotNull()
]);
orReduction(...keys: Array<string>): void
By providing the layers keys, orReduction
will reduce the referenced layers to a single layer, that resolve to true if at least on of the referenced layers resolved to true.
- Example :
const guardian = new Guardian();
guardian.on({
path: 'name',
errorMessage: 'name must start with B.'
}).add([
RunCustom('start-with-X', 'B')
]);
guardian.on({
path: 'data.age',
errorMessage: 'age is required & must be greater than 20.'
}).add([
NotNull(),
Gt(20)
]);
guardian.on({
path: 'data.list[$]',
errorMessage: 'all items in list are required',
each: true
}).add([
NotNull()
]);
// before orReduction --> 1 & 2 & 3
guardian.orReduction('1', '3');
// after orReduction --> (1 || 3) & 2
guardian.compile({
name: 'Bob',
data: {
age: 25,
list: [2, null]
}
});
console.log('summary:');
guardian.stackSummary();
guardian.run().then(errors => {
console.log('result:');
console.log(JSON.stringify(errors, undefined, 2));
});
// Output :
summary:
┌─────────┬────────┬─────────────────────┬────────────────┬─────┐
│ (index) │ Layer │ Name │ Path │ Key │
├─────────┼────────┼─────────────────────┼────────────────┼─────┤
│ 0 │ 'OR/1' │ [ 'start-with-X' ] │ 'name' │ 1 │
│ 1 │ 'OR/1' │ [ 'NotNull' ] │ 'data.list[$]' │ 3 │
│ 2 │ 1 │ [ 'NotNull', 'Gt' ] │ 'data.age' │ 2 │
└─────────┴────────┴─────────────────────┴────────────────┴─────┘
result:
[]
compile(target: any): void
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
run(): Promise<Array<any>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
disable(layerKey: number|string): void
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
stackSummary(prettyPrint: boolean): void
stackSummary(): Array<any>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
toMiddleware(target?: Function ): e.RequestHandler
toMiddleware(target?: string ): e.RequestHandler
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
- Example :
const guardian = new Guardian();
guardian.on({
path: 'email',
errorMessage: 'email field is required.'
}).add([
NotUndefined(),
NotNull(),
NotEmpty()
])
// the root object will be {req, res}
const logisterValidator = guardian.toMiddleware('req.body');
const app = express();
app.post('/login', logisterValidator, (req, res, next) => {
// request pass all validations ...
});
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
interface GuardianOptions {
layerKey?: string | number;
optional?: boolean;
errorMessage?: string;
each?: boolean;
disabled?: boolean
path: string | Array<string>;
}
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
const layerAttacher = guardian.on(...);
add(operations: LayerOperation): void
add(operations: Array<LayerOperation>): void
define a single validation layer with one or more layer-operations. where each operation holds the actual validation logic.
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.
interface LayerOperation {
(options: Partial<GuardianOptions>): SequentialLayer
}