quick-schema v0.5.1
Quick Schema
Quick Schema is a javascript module that allows user to perform json object validation.
Table of Content
- Quick Start - Define a schema - Validate an object
- Retrive Error Message
- Built-in Validators - Primitive types - Object - Array - Dictionary - Logical Operators - NOT - ONE_OF - ALL_OF - Special Validators - ANY - EXISTS - IS - STRINGIFIED - OPTIONAL - Regular Expression
- User Defined Validators - Alias - Self Reference - Custom Validator Logic
Quick Start
The minimal syntax to validate a specified obj
against a specified schema
:
Validate(obj, schema);
Define a schema
const { Validate, OPTIONAL, ONE_OF, IS } =
require("quick-schema");
const PersonSchema = {
name: {
first: String,
last: String,
middle: OPTIONAL(String)
},
age: Number,
pronouns: ONE_OF(IS("he"), IS("she"))
};
Validate an object
const Alice = {
name: { first: "Alice", last: "Silva" },
age: 35,
pronouns: "she"
};
const assert = require('assert');
let ok = Validate(Alice, PersonSchema);
assert(ok); // Evaluates to true
Retrive Error Message
Sometimes we want to know why an object failed the validation, this is expecially useful when we have a complex object. The Validate.WithReason(...)
function will return a concrete error message when the validation failed:
const CompanySchema = {
name: String,
employees: [
{
name: String,
title: OPTIONAL(String),
id: Number
}
],
};
const MyCompany = {
name: "MyCompany",
employees: [
{ name: "Alice", title: "CEO", id: 1 },
{ name: "Bob", title: "Manager", id: "2" },
{ name: "Carol", id: 3 }
]
};
const { ok, message } = Validate.WithReason(MyCompany, CompanySchema);
assert(!ok); // 'ok' evaluates to false
console.log(message); // Prints: 'root.employees[1].id' is not a number."
Built-in Validators
Primitive types
const { Validate, NULL, UNDEF } =
require("quick-schema");
assert(Validate("string", String));
assert(Validate(true, Boolean));
assert(Validate(0, Number));
assert(Validate(null, NULL));
assert(Validate(undefined, UNDEF));
Object
const { Validate, OPTIONAL } = require("quick-schema");
const ContactSchema = {
name: String,
phone: { country_code: Number, number: Number },
address: {
line_1: String,
line_2: OPTIONAL(String),
city: String,
state: String,
zip_code: Number,
country: String
},
note: "" // extra property (i.e. properties not metioned in schema) is OK
};
assert(Validate({
name: "Steven",
phone: { country_code: 1, number: 5555555555 },
address: {
line_1: "50 W 34St",
city: "Big Apple",
state: "NY",
zip_code: 10000,
country: "US"
}
}, ContactSchema));
Array
const { Validate } = require("quick-schema");
const NumberArraySchema = [Number];
let ok = Validate([1,1,2,3,5,8], NumberArraySchema);
assert(ok);
ok = Validate([1,"1",2,3,5,8], NumberArraySchema);
assert(!ok);
Dictionary
Use the Dictionary
validator to validate a mapping (from string to another type):
const { Validate, DICT } = require("quick-schema");
const ImdbRatingSchema= DICT(Number);
assert(Validate({
"The Shawshank Redemption": 9.3,
"The Godfather": 9.2,
"The Dark Knight": 9.1,
"The Lord of the Rings: The Return of the King": 9.0,
"Schindler's List": 9.0
}, ImdbRatingSchema));
You can combine object schema with dictionary schema:
const ImdbRatingSchema2 = DICT({ dictionary_name: String}, Number);
assert(Validate({
"dictionary_name": "IMDB Score",
"The Shawshank Redemption": 9.3,
"The Godfather": 9.2,
"The Dark Knight": 9.1,
"The Lord of the Rings: The Return of the King": 9.0,
"Schindler's List": 9.0
}, ImdbRatingSchema2));
Logical Operators
NOT
const { Validate, NOT } = require("quick-schema");
let ok;
ok = Validate("1", NOT(Number));
assert(ok);
ok = Validate(1, NOT(Number));
assert(!ok);
ONE_OF
const { Validate, ONE_OF } = require("quick-schema");
let ok;
ok = Validate(1, ONE_OF(Number, String));
assert(ok);
ok = Validate("", ONE_OF(Number, String));
assert(ok);
ok = Validate(true, ALL_OF(Number, String));
assert(!ok);
ALL_OF
const { Validate, ALL_OF } = require("quick-schema");
const EmployeeSchema = {
name: String,
title: String
};
const PersonSchema = {
name: String,
age: Number,
};
assert(Validate({
name: "Steven",
title: "Individual Contributor",
age: 33
}, ALL_OF(EmployeeSchema, PersonSchema)));
Special Validators
ANY
ANY
validator will match any value.
const { Validate, ANY } = require("quick-schema");
assert(Validate({}, ANY));
assert(Validate(false, ANY));
assert(Validate(undefined, ANY));
Note: ANY
validator will always return a match, even if the property does not exist:
assert(Validate({}, { data : ANY }));
EXISTS
EXISTS
validator will match any value, if such property exists.
const { Validate, NOT, EXISTS } = require("quick-schema");
const schema = {
name: EXISTS,
nick_name: NOT(EXISTS)
};
let ok;
ok = Validate({ name: "Nina" }, schema);
assert(ok); // ok because property '.name' exists, and '.nick_name' does not exist.
ok = Validate({ }, schema);
assert(!ok); // !ok because property '.name' does not exist.
ok = Validate({ name: "Catherine", nick_name: "Kay" }, schema);
assert(!ok); // !ok because property 'nick_name' does exist.
IS
IS
validator matches exact value:
const { Validate, IS } = require("quick-schema");
let ok;
ok = Validate(1, IS(1));
assert(ok);
ok = Validate(2, IS(1));
assert(!ok);
// '.lang' must be one of "C++", "Javascript" or "Go"
ok = Validate({ lang: "C++" }, { lang: ONE_OF(IS("C++"),
IS("Javascript"),
IS("Go")) });
assert(ok);
STRINGIFIED
STRINGIFIED
validator will match a string that can be JSON.parse(...)
to a specified type:
const { Validate, STRINGIFIED } = require("quick-schema");
assert(Validate("1", STRINGIFIED(Number)));
assert(Validate('{ "name": "Maggie" }', STRINGIFIED({ name: String })));
OPTIONAL
const { Validate, OPTIONAL } = require("quick-schema");
const Schema = {
name: String,
salary: OPTIONAL(Number)
};
assert(Validate({ name: "Summer" }, Schema)); // ok because '.salary' is optional
assert(Validate({ name: "Summer", salary: 100 }, Schema));
Regular Expression
const { Validate } = require("quick-schema");
const Schema = {
name: /^Andrew Jack(son)?$/
};
let ok;
ok = Validate({ name: "Andrew Jackson"}, Schema);
assert(ok);
ok = Validate({ name: "Andrew Jack"}, Schema);
assert(ok);
ok = Validate({ name: "Andy Jack" }, Schema);
assert(!ok);
User Defined Validators
User defined validators is very useful, they can be used to:
- Simplify schema definition
- Code reuse
- Enable validator self reference
- Create custom validator logic
User defined validators must be supplied in form of User Type Library:
const Library = {
"User Type Name": <User Type Definition>
};
To supply a library to the Validator
function:
Validate(obj, schema, library);
Alias
const { Validate, ALL_OF } = require("quick-schema");
const Library = {
// Define an alias type "Person"
"Person": {
name: String,
},
// Define an alias type "Employee"
// Note that "Employee" type depends on "Person"
"Employee": ALL_OF("Person", { salary: Number })
};
const employees = [ { name: "Alice", salary: 100 },
{ name: "Bob", salary: 100 } ];
// Referencing user type "Employee" in schema
assert(Validate(employees, ["Employee"], Library));
Self Reference
Validator self reference can be achieved via alias:
const { Validate, ANY, OPTIONAL } = require("quick-schema");
const Library = {
"LinkedList": {
next: OPTIONAL("LinkedList"),
data: ANY
}
};
const node1 = { data: 3721 };
const node2 = { data: 360, next: node1 };
assert(Validate(node2, "LinkedList", Library));
Custom Validator Logic
We can create a user defined validator with custom validator logic
const Library = {
"PositiveNumber": (num) => {
return num > 0;
}
};
let ok;
ok = Validate(1, "PositiveNumber", Library);
assert(ok);
ok = Validate(-1, "PositiveNumber", Library);
assert(!ok);
The custom validator function can return either a boolean, undefined, or a string:
|Return Value|Interpretation|
|------------|--------------|
|true
|Success|
|false
|Failed|
|undefined
|Success|
|string|Failed, "error message" will be set to the string|
|all other|Invalid return value|