Schema-Inspector is powerful tool to validation or sanitize javascript object.
It's disigned to work both client-side and server-side. Although originally
designed for use with node.js, it can also be used directly
in the browser.
Schema-Inspector has to be very scalable, and allow asynchronous and synchronous
calls.
### type
- type: string, array of string.
- usable on: any.
- possible values
string
number
integer
boolean
null
date
(constructor === Date)object
(constructor === Object)array
(constructor === Array)any
(it can be anything)
Allow to check property type. If the given value is incorrect, then type is not
checked.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'number' },
ipsum: { type: 'any' },
dolor: { type: ['number' 'string', 'null'] }
}
};
var c1 = {
lorem: 12,
ipsum: 'sit amet',
dolor: 23
};
var c2 = {
lorem: 12,
ipsum: 34,
dolor: 'sit amet'
};
var c3 = {
lorem: 12,
ipsum: [ 'sit amet' ],
dolor: null
};
var c4 = {
lorem: '12',
ipsum: 'sit amet',
dolor: new Date()
};
si.validate(schema, c1);
si.validate(schema, c2);
si.validate(schema, c3);
si.validate(schema, c4);
### optional
- type: boolean.
- default: false.
- usable on: any.
This field indicates whether or not property has to exist.
Example
var si = require('schema-inspector');
var schema1 = {
type: 'object',
properties: {
lorem: { type: 'any', optional: true }
}
};
var schema2 = {
type: 'object',
properties: {
lorem: { type: 'any', optional: false }
}
};
var c1 = { lorem: 'ipsum' };
var c2 = { };
si.validate(schema1, c1);
si.validate(schema1, c2);
si.validate(schema2, c1);
si.validate(schema2, c2);
### uniqueness
- type: boolean.
- default: false.
- usable on: array, string.
If true, then we ensure no element in candidate exists more than once.
Example
var si = require('schema-inspector');
var schema = {
type: 'array',
uniqueness: true
};
var c1 = [12, 23, 34, 45];
var c2 = [12, 23, 34, 12];
si.validate(schema, c1);
si.validate(schema, c2);
### pattern
- type: string, RegExp object, array of string and RegExp.
- usable on: string.
- Possible values as a string:
void
, url
, date-time
, date
,
coolDateTime
, time
, color
, email
, numeric
, integer
, decimal
,
alpha
, alphaNumeric
, alphaDash
, javascript
, upperString
, lowerString
.
Ask Schema-Inspector to check whether or not a given matches provided patterns.
When a pattern is a RegExp, it directly test the string with it. When it's a
string, it's an alias of a RegExp.
Example
var si = require('schema-inspector');
var schema1 = {
type: 'array',
items: { type: 'string', pattern: /^[A-C]/ }
};
var c1 = ['Alorem', 'Bipsum', 'Cdolor', 'DSit amet'];
var schema2 = {
type: 'array',
items: { type: 'string', pattern: 'email' }
};
var c2 = ['lorem@ipsum.com', 'dolor@sit.com', 'amet@consectetur'];
si.validate(schema1, c1);
si.validate(schema2, c2);
### minLength, maxLength, exactLength
- type: integer.
- usable on: array, string.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'string', minLength: 4, maxLength: 8 },
ipsum: { type: 'array', exactLength: 6 },
}
};
var c1 = {
lorem: '12345',
ipsum: [1, 2, 3, 4, 5, 6]
};
var c2 = {
lorem: '123456789',
ipsum: [1, 2, 3, 4, 5]
};
si.validate(schema, c1);
si.validate(schema, c2);
### lt, lte, gt, gte, eq, ne
- type: number.
- usable on: number.
Check whether comparison is true:
- lt:
<
- lte:
<=
- gt:
>
- gte:
>=
- eq:
===
- ne:
!==
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'number', gt: 0, lt: 5 },
ipsum: { type: 'number', gte: 0, lte: 5 },
dolor: { type: 'number', eq: [0, 3, 6, 9] },
sit: { type: 'number', ne: [0, 3, 6, 9] }
}
};
var c1 = { lorem: 3, ipsum: 0, dolor: 6, sit: 2 };
var c2 = { lorem: 0, ipsum: -1, dolor: 5, sit: 3 };
si.validate(schema, c1);
si.validate(schema, c2);
### someKeys
- type: array of string.
- usable on: object.
Check whether one of the given keys exists in object (useful when they are
optional).
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
someKeys: ['lorem', 'ipsum']
properties: {
lorem: { type: 'any', optional: true },
ipsum: { type: 'any', optional: true },
dolor: { type: 'any' }
}
};
var c1 = { lorem: 0, ipsum: 1, dolor: 2 };
var c2 = { lorem: 0, dolor: 2 };
var c3 = { dolor: 2 };
si.validate(schema, c1);
si.validate(schema, c2);
si.validate(schema, c3);
### strict
- type: boolean.
- default: false.
- usable on: object.
Only key provided in field "properties" may exist in object.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
strict: true,
properties: {
lorem: { type: 'any' },
ipsum: { type: 'any' },
dolor: { type: 'any' }
}
};
var c1 = { lorem: 0, ipsum: 1, dolor: 2 };
var c2 = { lorem: 0, ipsum: 1, dolor: 2, sit: 3 };
si.validate(schema, c1);
si.validate(schema, c2);
### exec
- type: function, array of function.
- usable on: any.
Custom checker =). "exec" functions take two three parameter
(schema, post [, callback]). To report an error, use this.report([message])
.
Very useful to make some custom validation.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: {
type: 'number',
exec: function (schema, post) {
if (post === 3) {
this.report('must not equal 3 =(');
}
}
}
}
};
var c1 = { lorem: 2 };
var c2 = { lorem: 3 };
si.validate(schema, c1);
si.validate(schema, c2);
### properties
- type: object.
- usable on: object.
For each property in the field "properties", whose value must be a schema,
validation is called deeper in object.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: {
type: 'object',
properties: {
ipsum: {
type: 'object',
properties: {
dolor: { type: 'string' }
}
}
}
},
consectetur: { type: 'string' }
}
};
var c1 = {
lorem: {
ipsum: {
dolor: 'sit amet'
}
},
consectetur: 'adipiscing elit'
};
var c2 = {
lorem: {
ipsum: {
dolor: 12
}
},
consectetur: 'adipiscing elit'
};
si.validate(schema, c1);
si.validate(schema, c2);
### items
- type: object, array of object.
- usable on: array.
Allow to apply schema validation for each element in an array. If it's an
object, then it's a schema which will be used for all the element. If it's an
array of object, then it's an array of schema and each element in an array will
be checked with the schema which has the same position in the array.
Example
var si = require('schema-inspector');
var schema1 = {
type: 'array',
items: { type: 'number' }
};
var schema2 = {
type: 'array',
items: [
{ type: 'number' },
{ type: 'number' },
{ type: 'string' }
]
};
var c1 = [1, 2, 3];
var c2 = [1, 2, 'string!'];
si.validate(schema1, c1);
si.validate(schema1, c2);
si.validate(schema2, c1);
si.validate(schema2, c2);
### alias
- type: string.
- usable on: any.
Allow to display a more explicit property name if an error is encounted.
Example
var si = require('schema-inspector');
var schema1 = {
type: 'object',
properties: {
_id: { type: 'string'}
}
};
var schema2 = {
type: 'object',
properties: {
_id: { alias: 'id', type: 'string'}
}
};
var c1 = { _id: 1234567890 };
var r1 = si.validate(schema1, c1);
var r2 = si.validate(schema2, c1);
console.log(r1.format());
console.log(r2.format());
### error
- type: string.
- usable on: any.
This field contains a user sentence for displaying a more explicit message if
an error is encounted.
Example
var si = require('schema-inspector');
var schema1 = {
type: 'object',
properties: {
_id: { type: 'string' }
}
};
var schema2 = {
type: 'object',
properties: {
_id: { type: 'string', error: 'must be a valid ID.' }
}
};
var c1 = { _id: 1234567890 };
var r1 = SchemaInspector.validate(schema1, c1);
var r2 = SchemaInspector.validate(schema2, c1);
console.log(r1.format());
console.log(r2.format());
Sanitization
### type
- type: string.
- usable on: any.
- possible values
number
integer
string
boolean
date
(constructor === Date)object
(constructor === Object)
Cast property to the given type according to the following description:
- to number from:
- to integer from:
- number (12.34: 12)
- string ("12.34": 12)
- boolean (true: 1, false: 0)
- to string from:
- boolean (true: "true")
- number (12.34: "12.34")
- integer (12: "12")
- date ([object Date]: "Mon Feb 25 2013 12:03:25 GMT+0100 (CET)")
- array ([12, 23, 44]: '12,34,45')
- to date from:
- number (1361790386000 -> Mon Feb 25 2013 12:06:26 GMT+0100 (CET))
- string ("2013-02-25T11:06:26.704Z" -> Mon Feb 25 2013 12:06:26 GMT+0100 (CET))
("Mon Feb 25 2013 12:06:26 GMT+0100 (CET)" -> Mon Feb 25 2013 12:06:26 GMT+0100 (CET))
Example
var si = require('schema-inspector');
var schema = {
type: 'array',
items: { type: 'string' }
};
var c = [12.23, -34, true, false, 'true', 'false', [123, 234, 345]];
var r = SchemaInspector.sanitize(schema, c);
### optional
- type: boolean.
- default: true.
- usable on: any.
Property is set to schema.def
if not provided and if optional is false
.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'number', optional: false, def: 12 },
ipsum: { type: 'string', optional: true, def: 23 },
dolor: { type: 'string', def: 'NikitaJS, def: 34 } // (optional: true)
}
};
var c = { };
var r = SchemaInspector.sanitize(schema, c);
/*
c: {
lorem: 12 // Only lorem is set to 12 because it is not optional.
}
*/
### rules
- type: string, array of string.
- usable on: string.
- possible values:
upper
: Every character will be changed to uppercase.lower
: Every character will be changed to lowercase.title
: For each word (/\S*/g), first letter will be changed to uppercase, and the rest to lowercase.capitalize
: Only the first letter of the string will be changed to uppercase, the rest to lowercase.ucfirst
: Only the first letter of the string will be changed to uppercase, the rest is not modified.trim
: Remove extra spaces.
Apply the given rule to a string. If several rules are given (array), then they
are applied in the same order than in the array.
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'string', rules: 'upper' },
ipsum: { type: 'string', rules: [ 'trim', 'title'] }
}
};
var c = {
lorem: ' tHiS is sParTa! ',
ipsum: ' tHiS is sParTa! '
};
var r = SchemaInspector.sanitize(schema, c);
### min, max
- type: string, number.
- usable on: string, number.
Define minimum and maximum value for a property. If it's less than minimum,
then it's set to minimum. If it's greater than maximum, then it's set to
maximum.
Example
var si = require('schema-inspector');
var schema = {
type: 'array',
items: { type: 'number', min: 10, max: 20 }
};
var c = [5, 10, 15, 20, 25];
var r = SchemaInspector.sanitize(schema, c);
### minLength, maxLength
- type: integer.
- usable on: string.
Adjust string length to the given number.
TODO: We must be able to choose which character we want to fill the string with.
Example
var si = require('schema-inspector');
var schema = {
type: 'array',
items: { type: 'string', minLength: 8, maxLength: 11 }
};
var c = ['short', 'mediumSize', 'tooLongForThisSchema'];
var r = SchemaInspector.sanitize(schema, c);
### exec
- type: function, array of functions.
- usable on: any.
Custom checker =). "exec" functions take two three parameter
(schema, post [, callback]), and must return the new value. To report an
sanitization, use this.report([message])
. Very useful to make some custom
sanitization.
NB: If you don't want to return a differant value, simply return post
,
do not return nothing (if you do so, the new value will be undefined
).
Example
var si = require('schema-inspector');
var schema = {
type: 'array',
items: {
type: 'string',
exec: function (schema, post) {
if (typeof post === 'string' && !/^nikita$/i.test(post)) {
this.report();
return '_INVALID_';
}
return post;
}
}
};
var c = [ 'Nikita', 'lol', 'NIKITA', 'thisIsGonnaBeSanitized!' ];
var r = SchemaInspector.sanitize(schema, c);
### punctual use
When you need to use the same function in exec
field several time, instead of
saving the function and declaring exec
several times, just use custom field.
First you have to provide a hash containing a function for each custom field you
want to inject. Then you can call them in your schema with $"your field name".
For example if you
provide a custom field called "superiorMod", you can access itwith name
"$superiorMod".
Example
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'number', $divisibleBy: 5 },
ipsum: { type: 'number', $divisibleBy: 3 }
}
};
var custom = {
divisibleBy: function (schema, candidate) {
var dvb = schema.$divisibleBy;16
if (cndidate % dvb !== 0) {
this.report('must be divisible by ' + dvb);
}
}
};
var c = {
lorem: 10,
ipsum: 8
};
si.validate(schema, candidate, custom);
### extension
Sometime you want to use a custom field everywhere in your programme, so you may
extend Schema-Inspector to do so. Just call the method
si.Validation.extend(customFieldObject) or
si.Sanitization.extend(customFieldObject). If you want to reset, simply call
si.Validation.reset() or si.Sanitization.reset(). You also can remove a
specific field by calling si.Validation.remove(field) or
si.Sanitization.remove(field).
Example
var si = require('schema-inspector');
var custom = {
divisibleBy: function (schema, candidate) {
var dvb = schema.$divisibleBy;16
if (cndidate % dvb !== 0) {
this.report('must be divisible by ' + dvb);
}
}
};
var schema = {
type: 'object',
properties: {
lorem: { type: 'number', $divisibleBy: 5 },
ipsum: { type: 'number', $divisibleBy: 3 }
}
};
si.Validation.extend(custom);
var candidate = {
lorem: 10,
ipsum: 8
};
si.validate(schema, candidate);
### Context
Every function you declare as a custom parameter, or with exec
field will be
called with a context. This context allow you to access properties, like
this.report()
function, but also this.origin
, which is equal to the object
sent to si.validate()
or si.sanitize()
.
Example
var schema = { ... };
var custom = {
divisibleBy: function (schema, candidate) {
}
};
var candidate = [12, 23, 34, 45];
var r = si.validate(schema, candidate, custom);
Asynchronous call
### How to
All the example above used synchronous call (the simplest). But sometime you
want to call validation or sanitization asynchronously, in particular with
exec
and custom fields. It's pretty simple: To do so, just send a callback
as extra parameter. It takes 2 parameters: error and result. Actually
Schema-Inspector should send back no error as it should not throw any if called
synchronously. But if you want to send back and error in your custom function,
inspection will be interrupted, and you will be able to retrieve it in your
callback.
You also have to declare a callback in your exec
or custom function to make
Schema-Inspector call it asynchronously, else it will be call synchronously.
That means you may use exec
synchronous function normally even during
and asynchronous call.
Example
var si = require('schema-inspector');
var schema = { ... };
var candidate = { ... };
si.validate(schema, candidate, function (err, result) {
console.log(result.format());
});
Example with custom field
var si = require('schema-inspector');
var schema = { ... };
var candidate = { ... };
var custom = { ... };
si.validate(schema, candidate, custom, function (err, result) {
console.log(result.format());
});
Here a full example where you may have to use it:
var si = require('schema-inspector');
var schema = {
type: 'object',
properties: {
lorem: { type: 'number', $divisibleBy: 4 },
ipsum: { type: 'number', $divisibleBy: 5 },
dolor: { type: 'number', $divisibleBy: 0, optional: true }
}
};
var custom = {
divisibleBy: function (schema, candidate, callback) {
var dvb = schema.$divisibleBy;
if (typeof dvb !== 'number' || typeof candidate !== 'number') {
return callback();
}
var self = this;
process.nextTick(function () {
if (dvb === 0) {
return callback(new Error('Schema error: Divisor must not equal 0'));
}
var r = candidate / dvb;
if ((r | 0) !== r) {
self.report('should be divisible by ' + dvb);
}
callback();
});
}
};
var candidate = {
lorem: 12,
ipsum: 25
};
si.validate(schema, candidate, custom, function (err, result) {
console.log(result.format());
});