struct-js v1.1.5
Welcome
struct.js is a military-grade validation library, with focus on fluent type
definition and precise error reporting.
npm install struct-jsTerminology
A validator is a Function that returns either exactly true or the precise
description of all errors.
For simple values, the description is a String. For containers, the
description is a mapping of keys to their individual error description.
function equalsOne(object) {
return (object === 1) ? true : `Expected 1, not ${object}`
}A struct is an object where each key is:
- A built-in type (
String,Number,Boolean, orDate) - A
validatorfunction (equalsOne) - An array with a
structas its only element ([ String ]) - An object with a
structas its values ({ name: String })
const userStruct = {
name: {
first: String,
last: String
},
height: Number,
birth: Date,
flags: [ Boolean ]
}Validate
validate(object, struct) is the generic validator. It will verify that an object
matches a struct, and return either true or a description.
import { validate } from 'struct-js'
validate("hello", String) // true
validate(123, String) // "This should be of type String, not Number"Let's see struct.validate handle an invalid userStruct:
let invalidUser = {
name: {
first: false,
last: 1234
},
height: new Date(),
birth: NaN,
flags: [ true, 'not a flag', true ]
}
validate(invalidUser, userStruct){
name: {
first: 'This should be of type String, not Boolean',
last: 'This should be of type String, not Number'
},
height: 'This should be of type Number, not Date',
birth: 'This should be of type Date, not Number',
flags: { '1': 'This should be of type Boolean, not String' }
}validate() has two cousins:
isValid()returnstrueorfalse:isValid('string', String) // true isValid(1, String) // falserequireValid()throws aValidationErrorif nottrue:try { requireValid(1, String) } catch(ve) { console.log(ve.details) // the validation result console.log(ve.message) console.log(ve.stack) }
Advanced Validators
The recommended pattern for creating advanced validators is to use a factory,
a function that given parameters returns a validator. For example, a more
generic version of equalsOne:
function equals(number) {
return (object) =>
(object === number) ? true : `Expected ${number}, not ${object}`
}struct.js alredy comes with some useful factories. import them from the
module.
optional
optional(struct) allows an object to be null or undefined, validating
it against struct if not.
const struct = {
unimportant: optional(String)
}
validate({ unimportant: 'nothing' }, struct) // true
validate({ unimportant: null }, struct) // true
validate({}, struct) // trueinstanceOf
instanceOf(Class) verifies an object is an insance of a Class.
class X {}
const struct = {
'x': instanceOf(X)
}
validate({ x: new X() }, struct) // true
validate({ x: 'what?' }, struct){ x: 'This should be of type X, not String' }oneOf
oneOf(...structs) validates an object against many structs, returning true
if any validation is successful, an array of error descriptions otherwise.
const struct = {
secretCode: oneOf(String, Number)
}
validate({ secretCode: 123 }, struct) // true
validate({ secretCode: null }, struct){
secretCode: [
'This should be of type String, not null',
'This should be of type Number, not null'
]
}allOf
allOf(...structs) validates an object against many structs, returning true
only if all validations are successful, an array of error descriptions
otherwise.
const struct = {
name: allOf(String, minLength(4))
}
validate({ name: 'John' }, struct) // true
validate({ name: '!' }, struct){
name: [ 'This should be have length >= 4, not 1' ]
}inEnum
inEnum(validValues) ensures an object is found in an array of validValues.
const struct = {
status: inEnum([ 'draft', 'sent', 'deleted' ])
}
validate({ status: 'draft' }, struct) // true
validate({ status: 'other' }, struct){
status: 'This should be one of [draft,sent,deleted], not other'
}mapOf
mapOf(struct) ensures an object is a mapping of keys to struct values, returning
true if every own property passes validation, or a map of keys to errors
if not.
const struct = mapOf({ name: String })
validate({ bob: { name: "Bob" } }, struct) // true
validate({ bob: { foo: 1 } }, struct){
"bob": {
"name": "This should be of type String, not undefined",
"foo": "This property should not be present"
}
}Usage patterns
struct.js can be extremely effective at controlling code complexity and ensuring
correctness. Here are some patterns to explore.
Named structs
Assign names to structs, and compose them into complex type definitions:
const userStruct = {
name: String,
age : Number
}
const groupStruct = {
leader : userStruct,
members: [ userStruct ]
}