Skip to content

Latest commit

 

History

History
367 lines (249 loc) · 11.8 KB

Readme.md

File metadata and controls

367 lines (249 loc) · 11.8 KB

json-schema-valid

Please note this library is not ready for production use.

A modular javascript JSON Schema v4 validator.

Suitable for standalone use (see "validator object" mode below), or together with other components to handle dereferencing, correlation, hypermedia, etc.

If you are looking for a (mostly) complete JSON Schema toolkit, see json-schema-suite which bundles the components together.

Installation

component:

$ component install ericgj/json-schema-valid

npm:

$ npm install json-schema-valid-component

Examples

There are two basic modes: as a validator object, and as a Correlation binding.

Validator object:

  var Validator = require('json-schema-valid')

  var validator = new Validator()

  // if schema has already been parsed
  var valid = validator.validate(schema,instance);
  
  // if raw schema object
  var valid = validator.validateRaw(rawSchema,instance);
  
  // checking state
  validator.valid();           // boolean
  validator.error();           // validation errors wrapped in an Error object
  validator.errorTrace();      // array of error messages with indented levels
  validator.assertionTrace();  // array of all assertions made on instance
  validator.errorTree();       // tree structure of validation errors 
  validator.assertionTree();   // tree structure of all assertions

Correlation binding:

  var core = require('json-schema-core')
    , Schema = core.Schema
    , plugin = require('json-schema-valid')
   
  // attach plugin to Schema 
  Schema.use(plugin);

  // now once you have a correlation, you can call validate() on it
  var valid = correlation.validate();

  // handling validation errors
  correlation.on('error', function(err){
    console.log('validation error: %o', err);
  }

  // subschema for given instance property
  // resolving valid combination conditions (allOf, anyOf, oneOf)
  var subschema = correlation.subschema('foo');

  // resolved URI-template links, including for valid combination conditions
  var links = correlation.links();

  // coerced instance (i.e., type and defaults applied to copy of instance)
  var coerced = correlation.coerce().instance;

Note that "raw" assertion data (assertionTree(), assertionTrace()) are not currently available using the 'correlation binding' mode. The error trace and tree are available through the error object emitted after failed validation (see below, "Events").

Formats

The following JSON Schema v3 format validations are built-in:

  • datetime (ISO 8601)
  • date (YYYY-MM-DD)
  • time (HH:MM:SS)
  • utc (milliseconds since 1970-01-01 00:00 UTC)
  • regex
  • phone
  • uri
  • email

In addition, the following custom formats are available:

js-function

A custom format js-function is available which allows serialization of simple javascript expressions (using the to-function library).

You can use this for custom validation involving instance values. For instance, the rule "x must be greater than 2 times y" can be expressed in the schema as:

{
  "type": "object",
  "format": "js-function",
  "js-function": "x > 2 * _.y",
  "required": ["x","y"],
  "properties": {
    "x": { "type": "number" },
    "y": { "type": "number" }
  }
}

The expression is specified as a string (or object) value of the "js-function" key.

(Note the to-function library also allows "query-object" style conditions as well as strings, see its documentation for details.)

Of course, this custom format will be ignored by other implementations, so if you are concerned about portability, you may wish to avoid using this format.

Note however there is no current standard for custom validation involving several instance values (a typical use-case for js-function). The JSON Schema v5 spec will have such a standard for simple cases (see draft proposals).

non-blank

This format allows more expressive error messages for cases where empty-string values are considered missing. Instead of using { "minLength": 1 } and getting error messages like is less than the minimum length, you can use { "format": "non-blank" } and get is missing. Essentially, this format considers both null and zero-length string values to be missing.

Using custom formats

To use the custom formats listed above:

Validator.addFormat('js-function', 
  require('ericgj-json-schema-valid/format/js-function')
);

To use your own format:

Validator.addFormat('my-format', myFormatFunction);

API

Validator.prototype.validate( schema:Schema, instance:Object, [callback:Function] )

Validate given instance against given schema. Takes optional callback function. Callback receives array of valid schemas (i.e., the root-level schema plus any schemas valid through combination conditions). Callback is only run if validation succeeds (valid).

Validator.prototype.validateRaw( schema:Object, instance:Object, [callback:Function] )

Validate given instance against given raw schema (parsing schema first).

Validator.prototype.valid()

Result of the last validate() call (boolean).

Validator.prototype.error()

If the last validate() call returned false (invalid), then returns an error object that wraps the error state:

  • message is the top-level error message for the instance;
  • trace is an array of error messages for invalid branches (see errorTrace);
  • tree is a tree-structure of error state for all failed validation conditions (see errorTree).

Validator.prototype.errorTrace()

If the last validate() call returned false (invalid), then returns an array of error messages for invalid branches, indented according to context level.

Validator.prototype.errorTree()

If the last validate() call returned false (invalid), then returns a tree structure of all failed assertions on invalid branches:

  • assertions() returns an array of failed assertions on the current branch. Each assertion object contains, besides an error message, schema and instance state and other info.
  • branches() returns an array of branches (sub-contexts), each of which has its own assertions and branches.

This structure can be used for custom error handling/messaging.

Validator.prototype.assertionTrace()

Returns array of assertion messages for all validated branches of the last validate() call (regardless of whether valid or invalid).

Validator.prototype.assertionTree()

Returns tree structure of all assertions on all validated branches of the last validate() call (regardless of whether valid or invalid).

Validator.addType( key:String, validator:Function )

Add custom validation function. See type/*.js for examples of how to write validation functions.

Validator.addFormat( format:String, validator:Function|Regexp )

Add custom format validation function or regular expression to match. Note specifying a regular expression here is essentially like having named schema pattern properties.

Correlation#validate( [callback:Function] )

Validate correlation instance against correlation schema.

Correlation#resolveLinks()

Validate, and return links merged from all valid schemas, if valid.

Intended to be used with the hyperschema plugin, to provide links(), rel(), etc. methods to the correlation, when combination conditions are specified. If the hyperschema plugin is not used, this method returns undefined.

See test/tests.js for usage examples.

Correlation#subschema( property:String )

Validate, and get the subschema describing the given instance property. If multiple subschemas are valid, the subschema is normalized as a single allOf condition.

Intended to be used as the basis for correlation.getPath() for co-traversing the schema and instance, when combination conditions are specified.

See test/tests.js for usage examples.

Correlation#coerce()

Validate, and coerces instance (applies type and default) according to:

  1. the first valid schema that specifies either type or default or both;
  2. the "top-level schema", otherwise, whether instance is valid or invalid.

Note that the ordering of valid schemas cannot be relied on, so it is recommended that either the top-level schema specify type and/or default, or only one combination schema specify these.

Events

Correlation#emit('error', fn[err])

On validation failure, the correlation emits 'error' with the error. err.message is the first "top-level" error. err.trace is the error trace (equivalent of validator.errorTrace()). err.tree is the error tree (equivalent of validator.errorTree()).

Running tests

In browser:

  1. Run make to generate JSON Schema test suite files and build the component.

  2. Browse the file test/index.html. Tests are run via in-browser mocha.

In node:

  1. Run make node to generate JSON Schema test suite files.

  2. npm test

A note on dereferencing

Dereferencing schemas is not implemented here. It is assumed that schemas with JSON references ($ref) will have already been dereferenced, making use of an http client library. See for example json-schema-agent, which provides both correlation (via HTTP headers) and schema dereferencing.

My view is that dereferencing necessarily involves external resources (the HTTP stack) and thus should be cleanly separated from validation.

However, if you know that your schema files will only have internal (fragment) references, it is possible to dereference without loading external resources (what the spec refers to as inline vs. canonical dereferencing). For convenience, in the future I will add inline dereferencing to json-schema-core. For now, the underlying Schema data structure does provide an interface for manipulating references, so it is also possible to roll your own inline dereferencing.

TODO

  • add common format validators
  • make error data compatible with tv4 errors
  • consider emitting schema-level errors or 'error trees' / rework internal Context objects
  • more complete walk-through of how to use with json-schema-hyper, json-schema-agent, etc. (add to json-schema-suite).
  • bower and npm installation

Acknowledgements

The validation logic used in this library is about 90% cribbed from the geraintluff/tv4 javascript reference implementation. Thanks for that Geraint 🍻 , and thanks equally for your always-excellent documentation of how JSON Schema is supposed to work, both in the specs and on the json-schema email list.

Regular expression for datetime format thanks to Cameron Brooks.

Regular expression for uri format thanks to "Yaffle".

Regular expression for email format thanks to Jan Goyvaerts, regular-expressions.info.

License

MIT