js-match
Validates an entire Javascript object against a set of nested matchers. This can be useful to quickly validate:
- a JSON config file
- the structure of an HTTP request payload
Note: js-match
will always ignore extra fields, as long as the set of matchers passes. This conforms with the robustness principle of "be conservative in what you do, be liberal in what you accept".
Basic usage
npm install js-match --save
jsm = require 'js-match' person = name: match: 'string' age: match: 'number' # success errors = jsmvalidate name: 'Bob'age: 30personerrorsshouldeql # failure errors = jsmvalidate age: 'foo'personerrorsshouldeql path: 'name'error: 'required' path: 'age'value: 'foo'error: 'should be a number'
Matchers
Values can be tested against a default set of matchers, for ex:
match: 'string' match: 'number' match: 'boolean' match: 'ip' match: 'host' match: 'url' match: 'uri' match: 'file' match: 'dollars' match: 'uuid-v4' match: 'enum'values: 'foo''bar'
You can also register custom matchers for advanced logic:
jsmmatchers'custom-id'= if not valuematch /[0-9a-f]{10}/i return "should be an ID of the form 8d9f0ab3c5" jsmvalidate object name: match: 'string' uniqueId: match: 'custom-id'
Matchers can also take optional parameters:
jsmmatchers'age'= if value < optionsmin or value > optionsmax return "should be an age between and " jsmvalidate object name: match: 'string' age: match: 'age'min: 1max: 100
Matchers can also return custom messages:
person = name: match: 'string'message: 'this is a custom message' age: match: 'number' # success errors = jsmvalidate name: 'Bob'age: 30personerrorsshouldeql # failure errors = jsmvalidate name: 12age: 30personerrorsshouldeql path: 'name'value: 12error: 'this is a custom message'
Nested configs
js-match
supports nested objects, arrays, and primitives:
jsmvalidate object credentials: user: match: 'string' pass: match: 'string' machines: host: match: 'string' port: match: 'number' values: match: 'number'
which matches the following object:
Any errors will be returned with fully qualified paths, for ex:
path: 'credentials.user' error: 'required' path: 'machines[1].host' value: 1234 error: 'should be a string' path: 'values[3]' value: true error: 'should be a number'
Custom schemas
You can either nest the matchers directly, like above, or extract them into separate "schemas":
auth = accountNumber: match: 'integer' password: match: 'string' jsmvalidate object name: match: 'string' auth: schema: auth
You can also pass a function that dynamically returns a schema:
= if parenttype is 'A' match: 'number' else match: 'string' jsmvalidate object type: match: 'string' value: schema: dynamic
Required and optional fields
By default, all fields are assumed to be required. Fields can be manually marked as optional:
jsmvalidate object username: match: 'string' password: match: 'string'optional: true
Validation will ignore missing optional fields, but will run the matcher if an optional field is present.
E.g. it won't complain if password
isn't there, but will if password
is a number.
You could also use optional on a "schema" matcher:
account = number: match 'integer' suburb: match 'string' jsmvalidate object username: match: 'string' password: match: 'string' account: schema: accountoptional: true
Validation will pass if account
is missing, but will run the matcher if account
node is present. E.g. it will complain if you have the account
node without presenting the number
or suburb
leaf under the account node.
Arrays
You can also do more complex matching on arrays
You could also use optional on an array of simple matchers:
jsmvalidate object username: match: 'string' password: match: 'string' accountIds: match: 'number'optional: true
Validation will pass if accountIds
is missing, but will run the matcher if accountIds
node is present.
E.g it will complain if accountIds
is present but is not an array of numbers
You could also use optional on an array of schema:
account = number: match 'integer' suburb: match 'string' jsmvalidate object username: match: 'string' password: match: 'string' accounts: schema: accountoptional: true
Validation will pass if accounts
is missing, but will run the matcher if accounts
node is present.
E.g it will complain if accounts
is present but is not an array of accounts
You could specify the min and max length of an array of schema:
account = number: match 'integer' suburb: match 'string' jsmvalidate object username: match: 'string' password: match: 'string' accounts: schema: accountmin: 2max: 5
Validation will pass if accounts
is an array of accounts. With length 2-5
E.g it will complain if accounts
is an array of 6 accounts.