Another JSON Schema, simple & flexible & intuitive.
$ npm i another-json-schema --save
const AJS = require('another-json-schema')
const userSchema = AJS('userSchema', {
name: { type: 'string', required: true },
age: { type: 'number', gte: 18 },
gender: { type: 'string', enum: ['male', 'female'], default: 'male' },
email: { type: 'string', trim: true, isEmail: true }
})
// test `required`
console.log(userSchema.validate({ age: 18 }))
/*
{ valid: false,
error:
{ Error: ($.name: undefined) ✖ (required: true)
validator: 'required',
actual: undefined,
expected: { type: 'string', required: true },
path: '$.name',
schema: 'userSchema' },
result: { age: 18 } }
*/
// test `default`
const data = { name: 'nswbmw', age: 18 }
console.log(userSchema.validate(data))
/*
{ valid: true,
error: null,
result: { name: 'nswbmw', age: 18, gender: 'male' } }
*/
console.log(data)
// { name: 'nswbmw', age: 18, gender: 'male' }
// test `enum`
console.log(userSchema.validate({ name: 'nswbmw', age: 18, gender: 'lalala' }))
/*
{ valid: false,
error:
{ Error: ($.gender: "lalala") ✖ (enum: male,female)
validator: 'enum',
actual: 'lalala',
expected: { type: 'string', enum: ['male', 'female'], default: 'male' },
path: '$.gender',
schema: 'userSchema' },
result: { name: 'nswbmw', age: 18, gender: 'lalala' } }
*/
// test `gte`
console.log(userSchema.validate({ name: 'nswbmw', age: 17 }))
/*
{ valid: false,
error:
{ Error: ($.age: 17) ✖ (gte: 18)
validator: 'gte',
actual: 17,
expected: { type: 'number', gte: 18 },
path: '$.age',
schema: 'userSchema' },
result: { name: 'nswbmw', age: 17 } }
*/
// test `isEmail`
console.log(userSchema.validate({ name: 'nswbmw', email: 'myEmail' }))
/*
{ valid: false,
error:
{ Error: ($.email: "myEmail") ✖ (isEmail: true)
validator: 'isEmail',
path: '$.email',
actual: 'myEmail',
expected: { type: 'string', trim: true, isEmail: true },
schema: 'userSchema' },
result: { name: 'nswbmw', email: 'myEmail', gender: 'male' } }
*/
const AJS = require('another-json-schema')
const userSchema = AJS('userSchema', {
_id: { type: 'string', pattern: /^[0-9a-z]{24}$/, required: true },
name: { type: 'string' },
age: { type: 'number', gte: 18 },
gender: { type: 'string', enum: ['male', 'female'] }
})
const commentSchema = AJS('commentSchema', {
_id: { type: 'string', pattern: /^[0-9a-z]{24}$/, required: true },
user: userSchema,
content: { type: 'string' }
})
const postSchema = AJS('postSchema', {
_id: { type: 'string', pattern: /^[0-9a-z]{24}$/, required: true },
author: userSchema,
content: { type: 'string' },
comments: [commentSchema]
})
const post = {
_id: 'post11111111111111111111',
author: {
_id: 'user11111111111111111111',
name: 'nswbmw',
age: 100,
gender: 'male',
pet: 'cat'
},
content: 'lalala',
comments: [{
_id: 'comment11111111111111111',
user: {
_id: 'wrong_id',
name: 'user1',
age: 100,
gender: 'male'
},
content: 'sofa'
}]
}
console.log(postSchema.validate(post))
/*
{ valid: false,
error:
{ [Error: ($.comments[].user._id: "wrong_id") ✖ (pattern: /^[0-9a-z]{24}$/)]
validator: 'pattern',
actual: 'wrong_id',
expected: { type: 'string', pattern: /^[0-9a-z]{24}$/, required: true },
path: '$.comments[].user._id',
schema: 'userSchema' },
result:
{ _id: 'post11111111111111111111',
author:
{ _id: 'user11111111111111111111',
name: 'nswbmw',
age: 100,
gender: 'male' },
content: 'lalala',
comments: [ [Object] ] } }
*/
const AJS = require('another-json-schema')
const userSchema = AJS('userSchema', {
name: { type: 'string', required: true },
age: {
type: 'number',
gte: 18,
_customErrorMsg: {
gte: '您未满 18 岁'
}
}
})
// test `_customErrorMsg`
console.log(userSchema.validate({
name: 'nswbmw',
age: 17
}))
/*
{ valid: false,
error:
{ Error: 您未满 18 岁
validator: 'gte',
path: '$.age',
actual: 17,
expected: { type: 'number', gte: 18, _customErrorMsg: [Object] },
schema: 'userSchema' },
result: { name: 'nswbmw', age: 17 } }
*/
const AJS = require('another-json-schema')
AJS.register('adult', function (actual, expected, key, parent) {
return expected ? (actual > 18) : (actual <= 18)
})
const adultSchema = AJS('adultSchema', { type: 'number', adult: true })
console.log(adultSchema.validate(19))
// { valid: true, error: null, result: 19 }
console.log(adultSchema.validate(17))
/*
{ valid: false,
error:
{ Error: ($: 17) ✖ (adult: true)
validator: 'adult',
actual: 17,
expected: { type: 'number', adult: true },
path: '$',
schema: 'adultSchema' },
result: 17 }
*/
Custom ObjectId validator, check whether ObjectId then wrap _id
string to ObjectId.
const AJS = require('another-json-schema')
const validator = require('validator')
const toObjectId = require('mongodb').ObjectId
function ObjectId(actual, key, parent) {
if (!actual || !validator.isMongoId(actual.toString())) {
return false
}
parent[key] = toObjectId(actual)
return true
}
const postSchema = AJS('postSchema', {
commentIds: [{ type: ObjectId }]
})
const user = {
commentIds: [
'111111111111111111111111',
'222222222222222222222222'
]
}
console.log(postSchema.validate(user))
/*
{ valid: true,
error: null,
result: { commentIds: [ 111111111111111111111111, 222222222222222222222222 ] } }
*/
//validate specific field
console.log(postSchema._children.commentIds.validate('lalala'))
/*
{ valid: false,
error:
{ Error: ($.commentIds[]: "lalala") ✖ (type: ObjectId)
validator: 'type',
path: '$.commentIds[]',
actual: 'lalala',
expected: [ [Object] ],
schema: 'postSchema' },
result: 'lalala' }
*/
What's difference between number
and AJS.Types.Number
?
number
only check type, AJS.Types.Number
will try to convert value to a number, if failed then throw error.
const AJS = require('/Users/nswbmw/work/GitHub/Node.js/another-json-schema')
const postSchema = AJS('postSchema', {
commentIds: [{ type: AJS.Types.ObjectId }]
})
const user = {
commentIds: [
'111111111111111111111111',
'222222222222222222222222'
]
}
console.log(postSchema.validate(user))
/*
{ valid: true,
error: null,
result: { commentIds: [ 111111111111111111111111, 222222222222222222222222 ] } }
*/
//validate specific field
console.log(postSchema._children.commentIds.validate('lalala'))
/*
{ valid: false,
error:
{ Error: ($.commentIds[]: "lalala") ✖ (type: ObjectId)
validator: 'type',
path: '$.commentIds[]',
actual: 'lalala',
expected: [ [Object] ],
schema: 'postSchema' },
result: 'lalala' }
*/
const AJS = require('another-json-schema')
const userSchema = AJS('userSchema', {
_id: { type: 'number', range: [1, 100] }
})
const user = {
_id: 0
}
console.log(userSchema.validate(user))
/*
{ valid: false,
error:
{ Error: ($._id: 0) ✖ (range: 1,100)
validator: 'range',
actual: 0,
expected: { type: 'number', range: [Array] },
path: '$._id',
schema: 'userSchema' },
result: { _id: 0 } }
*/
console.log(userSchema.validate(user, { range: false }))
// { valid: true, error: null, result: { _id: 0 } }
NB: type
validator cannot ignore by passing false
.
Constructor.
Register a validator. eg:
AJS.register('adult', function (actual, expected, key, parent) {
return expected ? (actual > 18) : (actual <= 18)
})
Compile a schema. The following two ways are the same:
const userSchema = AJS('userSchema', {
_id: { type: 'string', pattern: /^[0-9a-z]{24}$/ },
name: { type: 'string' },
age: { type: 'number', gte: 18 },
gender: { type: 'string', enum: ['male', 'female'] }
})
const newSchema = new AJS()
const userSchema = newSchema.compile('userSchema', {
_id: { type: 'string', pattern: /^[0-9a-z]{24}$/ },
name: { type: 'string' },
age: { type: 'number', gte: 18 },
gender: { type: 'string', enum: ['male', 'female'] }
})
Use the compiled validator to validate an object. it will modify the original object and return it:
($.comments[].user._id: "wrong_id") ✖ (pattern: /^[0-9a-z]{24}$/)
pattern
,wrong_id
,{ type: 'string', pattern: /^[0-9a-z]{24}$/ }
,$.comments[].user._id
,userSchema
opts:
false
[]
. default: false
isXxx
validators, eg: isEmail. type
validator must be string
or AJS.Types.String
.see test.
$ npm test (coverage 100%)
MIT