Chk has been mothballed in favor of its offspring scrub (https://github.com/3meters/scrub) Scrub needed to make some compatibility-breaking api changes, and so decamped to a new name. Chk works fine and I'll happily fix bugs or accept PRs if you need them, but if you're just starting, head to scrub.
Javascript's loose typing is lovely, except when it is not. chk lets you validate any value aginst any schema that you define.
npm install chk
Call chk passing in a value and a schema. Chk returns null on success or the first error it encouters on failure.
var chk = require('chk')
var schema = {type: 'string'}
var val = 'foo'
var err = chk(val, schema) // err is null
val = 1
err = chk(val, schema) // err is Error with code 'badType'
schema = {
str1: {type: 'string'},
num1: {type: 'number'}
}
err = chk({str1: 'foo', num1: 2}, schema) // err is null
err = chk({str1: 2}, schema) // err is Error with code 'badType'
schema = {s1: {type: 'string', required: true}}
err = chk({s1: 'foo', s2: 'bar'}, schema) // err is null
err = chk({s2: 'bar'}, schema) // err is Error with code 'missingParam'
schema = {type: 'string', value: 'one|or|another'}
err = chk('or', schema) // err is null
err = chk('notOne', schema) // err is Error wtih code 'badValue'
schema = {foo: {type: 'string'}}
err = chk({foo: 'hello', bar: 'goodbye'}, schema) // err is null
err = chk({foo: 'hello', bar: 'goodbye'}, schema, {strict: true}) // err is Error with code 'badParam'
schema = {n1: {
type: 'number',
value: function(v) {
if (v > 0) return null
else return new Error('n1 must be greater than zero')
}
}}
or
schema = {
a1: {type: 'array', value: {
type: 'object',
validate: function(v) {
if (v.n1 > v.n2) return new Error('object.n1 must be greater than object.n2')
return null
}
}}
}
Passing data to validators is easy. Within your validator, the this object refers to the top-level passed-in value, and the options object is passed through
var schema = {
n1: {type: 'number', default: 0},
n2: {type: 'number', validate: n2Validate}
}
function n2Validate(v, options) {
if (v !== this.n1) return 'n2 must equal n1'
if (options.foo) return 'options.foo must not be'
}
chk({n1:1, n2:1}, schema) // null
chk({n1:1, n2:2}, schema) // Error: 'n2 must equal n1'
chk({n1:1, n2:1}, schema, {foo:true}) // Error: 'options.foo must not be'
schema = {val1: {type: 'string|number|date'}}
schema = {
s1: {type: 'string'}
s2: {type: 'string', default: 'goodbye'}
}
val = {s1: 'hello'}
err = chk(val, schema) // err is null
console.log(val) // {s1: 'hello', s2: 'goodbye'}
Handy for casting numbers or booleans from query strings
schema = {n1: {type: 'number'}, b1: {type: 'boolean'}}
val = {n1: '12', b2: 'true'}
err = chk(val, schema) // err is null
console.log(val) // {n1: 12, b2: true} // types have been cast from string to target type
val = {n1: '12', b2: 'true'}
err = chk({n1: '12', b2: 'true'}, schema, {doNotCoerce: true}) // coercion off, err is Error with code 'badType'
schema = {
s1: {type: 'string'},
o1: {type: 'object', value: {
n1: {type: 'number', required: true},
d1: {type: 'date'},
o2: {type: 'object', value: {
s1: {type: 'string', default: 'I am deep in my nest'}
}
}
}
Nested schemas are applied to each element in the array
schema = {a1: {type: 'array', value: {type: 'number'}}}
err = chk({a1: [1,2,3]}) // err is null
err = chk({a1: [1, 2, '3']}) // err is Error with code 'badType'
schema = {
{type: 'array' value: {type: 'object', value: {s1: {type: 'string'}, n1: {type: 'number'}}}
}
var err = chk([{s1: 'foo', n1: 1}, {s1: 'bar', n1: 2}]) // err is null
var err = chk([{s1: 'foo', n1: 1}, {s1: 'bar', n1: 'baz'}]) // err is Error with code 'badType'
Options and their defaults are:
{
strict: false, // do not allow unspecified properties of objects
ignoreDefaults: false, // do not set default values, handy for db updates
ignoreRequired: false, // do not enforce required, handy for db updates
doNotCoerce: false, // do not coerce types
log: false // log the arguments to each recursive chk call,
// handy for debugging deeply nested schemas
}
Options can be set as an optional third argument to the top level call, or as properties of any schema or sub-schema. They remain set for all children unless they are overridden. For example, a top-level schema can be strict, meaning no unrecognized properties are allowed, except for one property, which can be unstrict, allowing un-specified sub-properties, except for one of its sub-properties, which must be strict, etc. For example:
schema = {
o1: {type: 'object', value: {
s1: {type: 'string'},
s2: {type: 'string'},
},
o2: {type: 'object', strict: false, value: {
s1: {type: 'string'},
s2: {type: 'string'},
o1: {type: 'object', strict: true: value: {
n1: {type: 'number'}
}
}
}
val = {
o1: {s1: 'foo', s2: 'bar'},
o2: {s1: 'foo', s2: 'bar', s3: 'baz}
}
err = chk(val, schema, {strict: true}) // err is null because o2 strict attribute overrode option
val.o2.o1 = {n2: 100}
err = chk(val, schema, {strict: true}) // err is Error because schema.o2.o1 does not allow properties other than n1
Contributions welcome. Run node test.js. Additions and improvements to test.js particularly welcome.
Copyright (c) 2013 3meters. All rights reserverd.
MIT