validate#
Validate JavaScript data with small, declarative rule objects.
Install#
npm i @nodedk/validate
Usage#
var validate = require('@nodedk/validate')
var schema = {
name: {
required: true,
is: 'string'
},
age: {
is: 'integer',
gte: 18
}
}
var data = {
name: 'Kim',
age: 32
}
var issues = validate(schema, data)
// null
validate(schema, data) is synchronous and leaves data unchanged. schema
maps field paths to rule objects; data is the object to inspect. Unknown
rule names are ignored. Validation returns null when the data is valid. Otherwise, it returns issues
grouped by their concrete field paths:
var data = {
age: 15
}
var issues = validate(schema, data)
// {
// name: [{ rule: 'required' }],
// age: [{ rule: 'gte', value: 18 }]
// }
Most rules skip missing fields. Use required: true when a field must exist. A
present null value is not considered missing; is: 'null' requires an
explicitly present null value.
Nested fields#
Use dotted paths for nested object fields:
var schema = {
user: {
required: true,
is: 'object'
},
'user.profile.email': {
required: true,
is: 'email'
}
}
var data = {
user: {
profile: {
email: 'kim@example.com'
}
}
}
validate(schema, data)
// null
Known array indices use the same notation:
var schema = {
'users.0.email': {
required: true,
is: 'email'
}
}
Wildcards#
* matches every immediate child of an array or object.
Arrays#
Validate every item in an array:
var schema = {
tags: {
required: true,
is: 'array',
min: 1
},
'tags.*': {
is: 'string'
}
}
var data = {
tags: ['node', 42, false]
}
var issues = validate(schema, data)
// {
// 'tags.1': [{ rule: 'is', value: 'string' }],
// 'tags.2': [{ rule: 'is', value: 'string' }]
// }
Objects#
Wildcards also validate every value in an object:
var schema = {
'flags.*': {
is: 'boolean'
}
}
var data = {
flags: {
admin: true,
editor: 'yes',
beta: false
}
}
var issues = validate(schema, data)
// {
// 'flags.editor': [{ rule: 'is', value: 'boolean' }]
// }
Arrays of objects#
var schema = {
users: {
is: 'array'
},
'users.*': {
is: 'object'
},
'users.*.email': {
required: true,
is: 'email'
}
}
var data = {
users: [{ email: 'a@example.com' }, { email: 'invalid' }, {}]
}
var issues = validate(schema, data)
// {
// 'users.1.email': [{ rule: 'is', value: 'email' }],
// 'users.2.email': [{ rule: 'required' }]
// }
Nested arrays and objects#
Use multiple wildcards for data with several collection levels:
var schema = {
'companies.*.teams.*.members.*.email': {
required: true,
is: 'email'
}
}
var data = {
companies: {
nodedk: {
teams: [
{
members: [{ email: 'ok@example.com' }, { email: 'invalid' }]
}
]
}
}
}
var issues = validate(schema, data)
// {
// 'companies.nodedk.teams.0.members.1.email': [
// { rule: 'is', value: 'email' }
// ]
// }
Consecutive wildcards validate nested arrays:
var schema = {
matrix: {
is: 'array'
},
'matrix.*': {
is: 'array'
},
'matrix.*.*': {
is: 'number'
}
}
An empty object or array has no wildcard matches. Use min, max, or length
on the collection itself when its size matters.
Wildcard paths only validate branches that exist. Require each parent whose
existence matters, and use min: 1 when a collection must contain an item:
var schema = {
companies: {
required: true,
is: 'object'
},
'companies.*.teams': {
required: true,
is: 'array',
min: 1
},
'companies.*.teams.*.email': {
required: true,
is: 'email'
}
}
Fixed paths do not have this restriction. Requiring user.profile.email
reports an issue at that path when any part of the fixed chain is missing.
Common rules#
Rules can be combined on the same field:
var schema = {
username: {
required: true,
is: 'string',
min: 3,
max: 30,
format: /^[a-z0-9-]+$/
},
score: {
is: 'number',
gte: 0,
lte: 100
},
status: {
in: ['active', 'disabled']
}
}
Each rule’s value is its expected value or configuration:
required: true: rejectundefined. Allowsnulland empty strings; combine withisandminwhen those should be rejected.is: typeoris: [type, ...]: accept any listed type. Unknown type names pass. Missing values are skipped unless the list containsnullorundefined;nullalone requires an explicit null value.isnt: typeorisnt: [type, ...]: inverse ofis, including its handling of missing values.eq: value,ne: value: strict equality or inequality; objects compare by identity, not contents.gt: value,gte: value,lt: value,lte: value: direct JavaScript comparisons. Combine withisto constrain the value’s type.in: values,nin: values: membership in an array usingindexOf.ninallowsnulleven if listed.length: number: exact.length.min: number,max: number: inclusive.lengthbounds. Use with strings and arrays; ordinary objects do not have a length.format: regexp: callregexp.test(value). Use a RegExp withoutgorywhen reusing a schema, since those flags advance its internal position.dateformat: string: exact calendar/time representation; see Dates below.
Rules other than required, is, and isnt skip undefined. Comparison,
length, and format rules reject null. All failing rules are collected in
schema order. Issues have { rule, value }, except required, which has
only { rule: 'required' }.
Types#
Use is to validate a value's type or format:
var schema = {
email: {
is: 'email'
},
count: {
is: 'integer'
},
enabled: {
is: 'boolean'
}
}
Several types can be allowed:
var schema = {
result: {
is: ['string', 'null']
}
}
Type reference#
array— an array, as determined byArray.isArray.base64— a standard padded Base64 string. URL-safe Base64 is not accepted.boolean—trueorfalse.date— a valid JavaScriptDateobject. Date strings are not accepted.datestring— a valid UTC timestamp ending inZ, with up to nine fractional-second digits.decimal— a JavaScript number other thanNaNthat is not an integer.domain— a string such asexample.comorapi.example.com.email— a string with text before and after@and a domain suffix.hex— a non-empty hexadecimal string.id— any string or integer. It does not require UUID syntax.integer— a number accepted byNumber.isInteger.ip— an IPv4 or IPv6 address.ipv4— an IPv4 address.ipv6— an IPv6 address.isodate— a valid calendar date inYYYY-MM-DDform.null— exactlynull.number— any JavaScript number exceptNaN, including integers.object— any non-null object that is not an array.slug— lowercase letters and numbers separated by single hyphens, such asmy-page-2.string— any JavaScript string, including an empty string.undefined— exactlyundefined, including a missing fixed field.url— an HTTP or HTTPS URL string.uuid— any 8-4-4-4-12 hexadecimal UUID string, regardless of version.uuidv7— an 8-4-4-4-12 hexadecimal UUID string with version7.
date and undefined describe JavaScript values that do not survive a JSON
serialize-and-parse cycle in the same form.
Dates#
Use isodate for calendar dates without a time or timezone:
var schema = {
birthday: {
is: 'isodate'
}
}
validate(schema, { birthday: '2026-07-19' })
// null
Use datestring for UTC timestamps:
var schema = {
created: {
is: 'datestring'
}
}
validate(schema, { created: '2026-07-19T12:30:00.123456789Z' })
// null
datestring rejects local timestamps and numeric timezone offsets. It accepts
seconds with an optional fraction containing one to nine digits.
Use dateformat for an exact custom representation:
var schema = {
published: {
dateformat: 'YYYY-MM-DD HH:mm:ss'
}
}
validate(schema, { published: '2026-07-19 14:30:00' })
// null
dateformat supports YYYY, MM, DD, HH, mm, ss, and SSS. Other
characters are treated as literals. Calendar dates and time ranges are
validated after the format is matched.
Path conventions#
- Dots separate path segments.
- Numeric segments address known array indices.
*matches every immediate own child of an object or array.- Dots and literal
*segments are not supported in data keys. - Extra fields that do not appear in the schema are ignored.
Created by Vidar Eldøy