@knno/valid
v1.4.0
Published
A simple data validation toolkit.
Readme
@knno/valid
Description
A TypeScript/JavaScript validation toolkit.
Installation
npm i @knno/validWhat this validation tool can do?
- Validate user-provided data early without putting validation logic in business code
- Structured validation rules enable automatic API documentation generation
- TypeScript support with type inference
- Customizable error messages
- Composable and reusable validation rules
Getting Started
import {Schema, string} from '@knno/valid';
// 1. Define validation rule
const rule = string(min(10), max(100));
// 2. Create validator
const schema = new Schema(rule);
// 3. Validate data
try {
schema.validate('Hello World!');
} catch (e) {
console.log(e.message); // Handle validation error
}Major Rule Definitions
- need()
// input can not be undefined or null
let rule = need();
// input can not be undefined or null and it must be a string
let rule = need(string());
// must be a number
let rule = need(number())
// must be a string or a number
let rule = need(union(string(), number()));
...need rule can only have primitive rule as it's sub rule, all supported sub rules are:
object, string, number, array, boolean, date, union- string()
// input should be a string, but if input not provide or it is null, it won't be regarded as error.
let rule = string();
// must be a string and cannot be null or undefined
let rule = need(string());
// string length must at least have 10 characters
let rule = string(min(10));
// string length must at most have 100 characters
let rule = string(max(100));
// string must match the regular expression
let rule = string(match(/^\d+$/));
// string must be a particular value
let rule = string(equal('abc'));
// verfication successful if all of the following conditions are met
let rule = string(min(10), max(100));
// verfication successful if any of the following conditions are met
let rule = string(any(equal('abc'), equal('def'), min(10), pattern(/^\d+$/)));
...- number()
let rule = number();
// value should great or equal to 10
let rule = number(min(10));
// value should great to 10
let rule = number(more(10));
// value should less or equal to 100
let rule = number(max(100));
// value should less 100
let rule = number(less(100));
let rule = number(range(10, 100));
let rule = number(equal(33));
let rule = number(any(equal(33), equal(44), equal(55)));- boolean()
let rule = boolean();
let rule = boolean(equal(true));- date()
let rule = date();
let rule = date(equal('2019-1-1'));
let rule = date(begin('2019-1-1'));
let rule = date(end('2020-1-1'));
let rule = date(before('2020-1-1'));
let rule = date(after('2019-1-1'));
let rule = date(between('2019-1-1', '2020-1-1'));
let rule = date(any(before('2019-1-1', between('2020-3-1', '2020-5-1'))));- object()
let rule = object();
let rule = object(
prop('name', string()),
prop('age', number()),
prop('extra', need()),
prop('detail', need(
object(
prop('id', need(number())),
prop('account', need(string()))
)
))
);- array()
let rule = array();
let rule = array(
item(need(
union(
object(
prop('id', need(number())),
prop('account', need(string()))
),
string()
)
)),
min(10), max(20)
);- union()
That's means value can be multiple types.
let rule = union(string(), number());
...- any() and all()
This two rules can combine a group of sub rules to reach more complex condition check.
let rule = string(any(min(10), all(pattern(/^A/), min(5))));- not()
Makes the match condition negated! (can only have one sub rule)
let rule = string(any(min(10), not(match(/^A/))));
let rule = string(not(any(min(10), match(/^A/))));
let rule = string(not(all(min(10), match(/^A/))));Above expression means either the string greater or equals to 10 character length or greater or equal to 5 character length and starts with character 'A'.
Rename Rule Name
You can rename any rule name as what your like, this usually can shorten your code:
import {Schema, string as s, number as n, need as r, object as o, prop as p} from '@knno/valid';
let rule = r(o(
p('name', r(s(min(1), max(30)))),
p('age', r(n(min(18))))
));Split Definition
To make the code clearly, usually you can split a complex definition to several parts:
let detail = need(object(
prop('name', need(string())),
prop('account', need(string())),
));
let users = need(array(
item(detail),
min(1), max(1000)
));
let rule = need(object(
prop('action', need(string())),
prop('users', users)
));
try {
let schema = new Schema(rule);
schema.validate({
action: 'show',
users: [{
name: 'user 1',
account: 'account1'
},{
name: 'user 2',
account: 'account2'
}]
});
} catch (e) {
console.log(e.message);
}Specify Custom Message
- mismatch()
There have a particular rule mismatch(), it can under the primitive type rule used to specify error message when input type doesn't match the expected type.
let rule = string(mismatch('There need a string'));- need()
let rule = need(object(), 'use custom message');- Other check rules
Any check rules can accept a string as last parameter as custom message.
let rule = string(max(20, 'String length cannot be more than 20 characters'));
Simplified type definition syntax
The define() function allows creating validation rules with type inference:
import { define, req, obj, str, num } from '@knno/valid';
// Define both type and validation rules
const userType = define(() =>
req(obj({
name: req(str(min(3))),
age: req(num())
}))
);
// Use inferred type
const user: typeof userType.type = {
name: "John",
age: 30
};
// Create validator
const validator = new Schema(userType.rule);Integration with @knno/web
Seamless integration with @knno/web framework for API parameter validation:
import { define, num, obj, str, req } from '@knno/valid';
import { DefaultContext, query, title, result, desc } from '@knno/web';
// Parameter definition
const paramsDef = define(() =>
req(obj({
id: req(num())
}))
);
// Request body definition
const bodyDef = define(() =>
req(obj({
field1: req(str(min(3))),
field2: req(num())
}))
);
@title('Sample API')
export default class SampleController {
@desc('API description...')
@query(paramsDef)
@result('None')
async post(ctx: DefaultContext): Promise<void> {
const params = ctx.getParams(paramsDef);
const payload = ctx.body.json(bodyDef);
// Use validated parameters...
}
}See @knno/web
NOTE:
Usually we don't need to specify any custom message, because the builtin error message will provide more detailed info.
That's all
If you find any problem please feel free to report to issues, I would appreciate your contribution.
