npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rjv

v5.0.0-alpha.9

Published

Reactive JSON Schema Validator

Downloads

196

Readme

RJV

Reactive JSON Schema Validator - a simplified JSON schema validator adapted for building frontend form validation tools, such as the rjv-react library for creating forms in ReactJS applications.

  • extends JSON schema with functional keywords which allow creating validation rules at runtime.
  • customizable error and warning messages

If you are looking for a server side data validation solution, you should choose another one, such as ajv

Install

# npm
npm i rjv

# yarn
yarn add rjv

Usage

Validating data

Validating scalar value

import { Validator } from 'rjv';

const schema = {
  type: 'number',
  minimum: 5,
  exclusiveMinimum: true,
}

const validator = new Validator(schema)

const data = 6;

validator
  .validateData(data)
  .then(result => console.log('is valid: ', result.valid)) // is valid: true

Validating object value

import { Validator } from 'rjv';

const schema = {
  properties: {
    login: {
      type: 'string',
      presence: true,
      format: 'email',
      minLength: 3,
    },
    password: {
      type: 'string',
      presence: true,
      minLength: 6,
      pattern: '',
    },
  },
}

const data = {
  login: '[email protected]',
  password: '',
}

const validator = new Validator(schema)

validator
  .validateData(data)
  .then(result => console.log('is valid: ', result.valid)) // is valid: false

Accessing data

The Ref is a main interface to access and change data. Each Ref points to a specific data property, to determine that property a path is being used. The path is a simple string working like a file system path, it could be absolute - /, /a/b/c or relative - ../b/c, b/c. The numeric parts of the path are treated as an array index, the rest as an object key. Refs are provided to the validation functions, also refs can be created manually or retrieved from any other Ref.

import { Ref, Storage, Validator } from 'rjv';

// data source
const data = {
  items: [1, 2, 3],
  obj: {
    prop: 'foo'
  }
}

// wrap data to a Storage object
const storage = new Storage(data);
const rootRef = new Ref(storage); // the same as - new Ref(storage, '/')

// getting values
console.log(rootRef.value); // { items: [1, 2, 3], obj: { prop: 'foo' } }

const objRef = rootRef.ref('obj');
// there is used a relative path which model resolves to the root path '/'
// or could be used an absolute path '/obj'
console.log(objRef.value); // { prop: 'foo' }

let propRef = rootRef.ref('obj/prop');  // get a ref to the "foo" property using model 
propRef = objRef.ref('prop'); // get a ref to the "foo" property using another ref
// the objRef resolves relative paths to the '/obj' path
propRef = objRef.ref('/obj/prop'); // get ref using absolute path
console.log(propRef.value); // 'foo'

const itemsRef = rootRef.ref('items');
console.log(itemsRef.value); // [1, 2, 3]
console.log(itemsRef.ref('0').value); // 1
console.log(itemsRef.ref('1').value); // 2
console.log(itemsRef.ref('../obj/prop').value); // 'foo'
console.log(itemsRef.ref('1').ref('../../obj/prop').value); // 'foo'

// changing values
propRef.value = 'bar';
console.log(propRef.value); // 'bar'
console.log(objRef.value); // { prop: 'bar' }
console.log(rootRef.value); // { items: [1, 2, 3], obj: { prop: 'bar' } }

// validating refs
const result = await (new Validator({ type: 'string' })).validateRef(propRef)
console.log('is valid: ', result.valid) // is valid: true

Inline validation

Besides, the standard JSON validation keywords there is an additional validate keyword, which allows you to place custom validation functions right in the schema. That functions receive a Ref instance to validate and must return a value which is resolved to a ValidateFnResult object according to the following rules:

  • a ValidateFnResult object is used as is
  • a string value - invalid result with error message { keyword: 'inline', description: `${value}` }
  • a boolean value:
    • true - valid result without warning message
    • false - invalid result with default error message { keyword: 'inline', description: 'Incorrect value' }

Validation function could be sync:

import { Validator, Ref, ValidateFnResult, types } from 'rjv';

const schema: types.ISchema = {
  properties: {
    password: {
      validate: (ref: Ref) => {
        const password = ref.value;

        if (typeof password === 'string') {
          if (password.length < 6) {
            // invalid value having an error message with
            // description - "Password must be at least 6 characters"
            // keyword - "inline"
            return 'Password must be at least 6 characters'
          }

          if (password.length < 8) {
            // valid value but has an additional warning message with
            // description - "Weak password"
            // keyword - "password"
            return new ValidateFnResult(true, 'Weak password', 'password')
          }

          // valid value without warning message
          return true
        }

        // invalid value having a default error message with
        // description - "Incorrect value"
        // keyword - "inline"
        return false
      },
    }
  }
};
const data = { password: '1234567' };

const validator = new Validator(schema);

const { valid, results } = await validator.validateData(data);
conosle.log(valid); // true
conosle.log(results['/'].messages[0].toString()); // Weak password

or async:

import { Validator, Ref, types } from 'rjv';

const schema: types.ISchema = {
  properties: {
    email: {
      presence: true,
      type: 'string',
      format: 'email',
      validate: async (ref: Ref) => {
        const value = ref.value;

        const res = await fetch(`/is-email-registered?email=${value}`);

        if (res === 'ok') {
          // invalid value
          return 'Email is already registered'
        }

        // valid value
        return true;
      },
    }
  }
};
const data = { email: '[email protected]' };

const validator = new Validator(schema);

// assume that the user was already registered
const { valid, results } = await validator.validateData(data);
conosle.log(valid); // false
conosle.log(results['/'].messages[0].toString()); // Email is already registered

Conditional validation

Conditional validation could be realized in two ways:

  • Declarative way - using keywords if/then/else and the applySchemas keyword to combine multiple if/then/else conditions.
  • Functional way - using the resolveSchema keyword, which is a function that takes a Ref instance and returns a JSON validation schema for the given ref.

Customizing validation messages

There are two options to customize error/warning messages:

  • Through the options param, these settings changes default keyword messages:
    import { Validator } from 'rjv';
       
    const validator = new Validator(
      { minLength: 6 },
      // options param
      {
        errors: {
        minLength: 'The value must be at least {limit} characters.',
        }
      }
    );
  • Through the error/errors and warning/warnings schema keywords, these setting will only be applied within the schema where they were declared:
    import { Validator } from 'rjv';
       
    const validator = new Validator(
      {
         minLength: 6,
         errors: {
           minLength: 'The value must be at least {limit} characters.'
         }
      },
    );

Adding validation keywords

TBD

API

Validator

The main class uses JSON schema for data validation.

new Validator(schema: ISchema, options?: Partial<IValidatorOptions>): Validator

Creates Validator instance:

import { Validator } from 'rjv';

const validator = new Validator({ type: 'string', presence: true })

IValidatorOptions:

An object representing a validator options

interface IValidatorOptions {
  /**
   * Coerce data types
   */
  coerceTypes: boolean;
  /**
   * Remove additional properties
   */
  removeAdditional: boolean;
  /**
   * Stop the property validation proccess on the first error
   */
  validateFirst: boolean;
  /**
   * A map with custom error messages
   */
  errors: { [keywordName: string]: string };
  /**
   * A map with custom warning messages
   */
  warnings: { [keywordName: string]: string };
  /**
   * An array of additional keywords
   */
  keywords: IKeyword[];
}

Default validator options:

const defaultOptions = {
  coerceTypes: false,
  removeAdditional: false,
  validateFirst: true,
  errors: {},
  warnings: {},
  keywords: []
}

validator.validateData(data: any, options?: Partial<IValidateFnOptions>): Promise<IValidationResult>

Validates data

import { Validator } from 'rjv';

const validator = new Validator({ type: 'string', presence: true })
validator
  .validateData('abc')
  .then((res) => console.log(res.valid)) // true

See IValidateFnOptions, IValidationResult

validator.validateStorage(storage: IStorage, options?: Partial<IValidateFnOptions>): Promise<IValidationResult>

Validates data wrapped in a Storage object

import { Validator, Storage } from 'rjv';

const validator = new Validator({ type: 'string', presence: true })
validator
  .validateData(new Storage('abc'))
  .then((res) => console.log(res.valid)) // true

See IValidateFnOptions, IValidationResult

validator.validateRef(ref: IRef, options?: Partial<IValidateFnOptions>): Promise<IValidationResult>

Validates data referenced by the Ref object

import { Validator, Storage } from 'rjv';

const validator = new Validator({ type: 'string', presence: true })
const storage = new Storage({
  foo: 'abc',
  bar: 123
})

validator
  .validateData(new Ref(storage, '/foo'))
  .then((res) => console.log(res.valid)) // true

validator
  .validateData(new Ref(storage, '/bar'))
  .then((res) => console.log(res.valid)) // false

IValidateFnOptions:

An object representing a validate process options, default values are inherited from the IValidatorOptions object

interface IValidatorOptions {
  /**
   * Coerce data types
   */
  coerceTypes: boolean;
  /**
   * Remove additional properties
   */
  removeAdditional: boolean;
  /**
   * Stop the property validation proccess on the first error
   */
  validateFirst: boolean;
}

IValidationResult:

An object representing a validate process result

interface IValidatorOptions {
  /**
   * Is the verified data valid?
   */
  valid: boolean;
  /**
   * Results map
   * Note: that some properties may have an undefined result
   * that means there is no applicable rules for the value type of the property
   * for example: schema { minimum: 10 } doesn't applicable for any non-number values,
   * because "minimum" keyword only works with numbers
   * You should avoid undefined results
   */
  results: {
    [path: string]: IValidateFnResult | undefined;
  };
}

See IValidateFnResult

Storage

Provides a simple get/set API to access data

new Storage(data: any): Storage

Creates Storage instance.

import { Storage } from 'rjv';

const storage = new Storage('some data');

storage.set(route: Array<string | number>, value: any): void

Sets new value to the specified property

import { Storage } from 'rjv';

const scalarStorage = new Storage('foo');
console.log(scalarStorage.get([])); // foo
scalarStorage.set([], 'bar');
console.log(scalarStorage.get([])); // bar

const objectStorage = new Storage({ prop: 'foo' });
console.log(objectStorage.get([])); // { prop: 'foo' }
objectStorage.set(['prop'], 'bar');
console.log(objectStorage.get([])); // { prop: 'bar' }

const arrayStorage = new Storage(['foo']);
console.log(arrayStorage.get([])); // ['foo']
arrayStorage.set([0], 'bar');
console.log(arrayStorage.get([])); // ['bar']

storage.get(route: Array<string | number>): any

Gets the value of the specified property

import { Storage } from 'rjv';

const storage = new Storage({
  a: 'a',
  b: {
    c: 'c',
    d: [123]
  }
});
console.log(storage.get([])); // { a: 'a', b: { c: 'c', d: [123] } }
console.log(storage.get(['a'])); // 'a'
console.log(storage.get(['b'])); // { c: 'c', d: [123] }
console.log(storage.get(['b', 'd', 0])); // 123 }

Ref

Represents a reference to a property of the data storage and provides access to the value of the property.

new Ref(storage: Storage, path = '/'): Ref

Creates Ref instance.

import { Storage, Ref } from 'rjv';

const ref = new Ref(new Storage('foo'));

Provided path must be absolute.

ref.ref(path: string): Ref

Resolves the path and gets a ref to the desired property. The path could be absolute or relative. If given path is relative it is resolved to the path of the current ref.

ref.setValue(value: any): void

ref.value = value

Change the value of the ref.

import { Storage, Ref } from 'rjv';

const ref = new Ref(new Storage('foo'));
// setter
ref.value = 'bar'; // set new value
// as function
ref.setValue('bar');  // the same

ref.getValue(): any

ref.value: any

Get the current value of the ref.

import { Storage, Ref } from 'rjv';

const ref = new Ref(new Storage('foo'));
// getter
ref.value; // foo
// as function
ref.getValue(); // foo

ValidationMessage

Implements IValidationMessage interface.

IValidationMessage

An object representing the error / warning messages.

export interface IValidationMessage {
  /**
   * `true` if it is a warning message, otherwise it is an error message
   */
  success: boolean;
  /**
   * the name of the keyword causing the error/warning
   */
  keyword: string;
  /**
   * the error/warning description
   * might have {bindingName} tags which can be replaced with values from the `bindings` field
   */
  description: string;
  /**
   * the additional values describing message
   */
  bindings: {};
}

new ValidationMessage(success: boolean, keyword: string, description: string, bindings?: {}): ValidationMessage

Create a validation message description object:

import { ValidationMessage } from 'rjv';

const message = new ValidationMessage(
  false,
  'format',
  'Should match format "{format}"',
  { format: 'email' }
);

console.log(message);
/*
{
  success: false,
  keyword: 'format',
  description: 'Should match format "{format}"',
  bindings: { format: 'email' }
}
*/

message.toString(): string

Returns a normalized description of the message, trying to replace {bindingName} tags of the description with the corresponding bindings values.

import { ValidationMessage } from 'rjv';

const message = new ValidationMessage(
  false,
  'format',
  'Should match format "{format}"',
  { format: 'email' }
);
console.log(message.toString()); // Should match format "email"

ValidateFnResult

Implements IValidateFnResult interface. Used by the build-in keywords and inline validation functions.

IValidateFnResult

An object describing the result of the value validating process.

interface IValidateFnResult {
  valid: boolean;
  messages: IValidationMessage[];
}

See IValidationMessage

new ValidateFnResult(valid: boolean, description?: string, keyword?: string, bindings?: {}): ValidateFnResult

Creates a validation result object.

import { ValidateFnResult } from 'rjv';

const result = new ValidateFnResult(
  false,
  'format',
  'Should match format "{format}"',
  { format: 'email' }
);

console.log(result);
/*
{
  valid: false,
  messages: [
    {
      success: false,
      keyword: 'format',
      description: 'Should match format "{format}"',
      bindings: { format: 'email' }
    }
  ]
}
*/

Keywords

Keywords for all types

type

This keyword requires that the data is of certain type (or some of the types)

Schema:

type Type = 'number' | 'integer' | 'string' | 'boolean' | 'array' | 'object' | 'null'

interface ISchema {
  type: Type | Type[]
}

Error message of the { type: ['number', 'string'] }:

{
  success: false,
  keyword: 'type',
  description: 'Should be {typesAsString}',
  bindings: { types: ['number', 'string'], typesAsString: 'number, string' },
}

enum

The value of the keyword should be an array of unique items of any types. The data is valid if it is deeply equal to one of items in the array.

Schema:

interface ISchema {
  enum: any[]
}

Error message of the { enum: [1, 2, 3] }:

{
  success: false,
  keyword: 'enum',
  description: 'Should be equal to one of the allowed values',
  bindings: { allowedValues: [1, 2, 3] }
}

const

The value of this keyword can be anything. If a function is specified as a value, the value will be resolved by calling this function and passing the current ref as an argument. The data is valid if it is deeply equal to the value of the keyword.

interface ISchema {
  const: any | ((ref: Ref) => any)
}

Error message of the { const: 123 }:

{
  success: false,
  keyword: 'const',
  description: 'Should be equal to constant',
  bindings: { allowedValue: 123 }
}

presence

The data is valid if it is not undefined and is not an empty string. If the trim option equals true and the value is a string, it will be trimmed.

interface ISchema {
  presence: boolean | {
    trim: boolean;
  }
}

Error message of the { presence: true }:

{
  success: false,
  keyword: 'presence',
  description: 'Should not be blank',
  bindings: { path: '/' }
}

Keywords for numbers

maximum / minimum and exclusiveMaximum / exclusiveMinimum

interface ISchema {
  maximum: number;
  minimum: number;
  exclusiveMaximum: boolean;
  exclusiveMinimum: boolean;
}

Error message of the { maximum: 123 }:

{
  success: false,
  keyword: 'maximum',
  description: 'Should be less than or equal {limit}',
  bindings: { limit: 123, exclusive: false }
}

Error message of the { maximum: 123, exclusiveMaximum: true }:

{
  success: false,
  keyword: 'maximum_exclusive',
  description: 'Should be less than {limit}',
  bindings: { limit: 123, exclusive: true }
}

Error message of the { minimum: 123 }:

{
  success: false,
  keyword: 'minimum',
  description: 'Should be greater than or equal {limit}',
  bindings: { limit: 123, exclusive: false }
}

Error message of the { maximum: 123, exclusiveMinimum: true }:

{
  success: false,
  keyword: 'minimum_exclusive',
  description: 'Should be greater than {limit}',
  bindings: { limit: 123, exclusive: true }
}

multipleOf

The value of the keyword should be a number. The data to be valid should be a multiple of the keyword value (i.e. the result of division of the data on the value should be integer)

Schema:

interface ISchema {
  multipleOf: number
}

Error message of the { multipleOf: 2 }:

{
  success: false,
  keyword: 'multipleOf',
  description: 'Should be multiple of {multiplier}',
  bindings: { multiplier: 2 }
}

Keywords for strings

maxLength / minLength

The data to be valid should have length satisfying this rule.

Schema:

interface ISchema {
  maxLength: number
  minLength: number
}

Error message of the { maxLength: 5 }:

{
  success: false,
  keyword: 'maxLength',
  description: 'Should not be longer than {limit} characters',
  bindings: { limit: 5 }
}

Error message of the { minLength: 5 }:

{
  success: false,
  keyword: 'minLength',
  description: 'Should not be shorter than {limit} characters',
  bindings: { limit: 5 }
}

pattern

The data to be valid should match the regular expression defined by the keyword value. Rjv uses new RegExp(value) to create the regular expression that will be used to test data.

Schema:

interface ISchema {
  pattern: string
}

Error message of the { pattern: '/\d/' }:

{
  success: false,
  keyword: 'pattern',
  description: 'Should match pattern {pattern}',
  bindings: { pattern: '/\d/' }
}

format

The data to be valid should match the format with this name.

Schema:

type Format = 'date' | 'time' | 'date-time' | 'email' | 'uri' | 'url' | 'uri-reference' | 'uri-template' | 'hostname' | 'ipv4' | 'ipv6' | 'regex'

interface ISchema {
  format: Format
}

Formats description:

  • date - full-date according to RFC3339.
  • time - time with optional time-zone.
  • date-time - date-time from the same source (time-zone is mandatory).
  • uri - full URI.
  • uri-reference - URI reference, including full and relative URIs.
  • uri-template - URI template according to RFC6570
  • url - URL record.
  • email - email address.
  • hostname - host name according to RFC1034.
  • ipv4 - IP address v4.
  • ipv6 - IP address v6.
  • regex - tests whether a string is a valid regular expression by passing it to RegExp constructor.

Error message of the { format: 'email' }:

{
  success: false,
  keyword: 'format',
  description: 'Should match format "{format}"',
  bindings: { format: 'email' }
}

Keywords for arrays

maxItems / minItems

The data array to be valid should not have more (less) items than the keyword value.

Schema:

interface ISchema {
  maxItems: number
  minItems: number
}

Error message of the { maxItems: 3 }:

{
  success: false,
  keyword: 'maxItems',
  description: 'Should not have more than {limit} items',
  bindings: { limit: 3 }
}

Error message of the { minItems: 3 }:

{
  success: false,
  keyword: 'minItems',
  description: 'Should not have fewer than {limit} items',
  bindings: { limit: 3 }
}

items / additionalItems

The value of the keyword should be an object or an array of objects.

If the keyword value is an object, then for the data array to be valid each item of the array should be valid according to the schema in this value. In this case the "additionalItems" keyword is ignored.

If the keyword value is an array, then items with indices less than the number of items in the keyword should be valid according to the schemas with the same indices. Whether additional items are valid will depend on "additionalItems" keyword.

Schema:

interface ISchema {
  items: Schema | Schema[]
  additionalItems: boolean | Schema
}

Error message of the { items: { type: 'number' } }:

{
  message: {
    keyword: 'items',
    description: 'Should have valid items',
    bindings: { invalidIndexes: [1] }
  }
}

Error message of the { items: [{ type: 'number' }, { type: 'number' }] }:

{
  message: {
    keyword: 'items_overflow',
    description: 'Should not have more than {limit} items',
    bindings: { limit: 2 }
  }
}

contains

The value of the keyword is a JSON Schema. The array is valid if it contains at least one item that is valid according to this schema.

Schema:

interface ISchema {
  contains: Schema
  additionalItems: boolean | Schema
}

Error message of the { contains: 123 }:

{
  success: false,
  keyword: 'contains',
  description: 'Should contain a valid item',
  bindings: {}
}

Keywords for objects

maxProperties / minProperties

The value of the keywords should be a number. The data object to be valid should have not more (less) properties than the keyword value.

Schema:

interface ISchema {
  maxProperties: number
  minProperties: number
}

Error message of the { maxProperties: 4 }:

{
  success: false,
  keyword: 'maxProperties',
  description: 'Should not have more than {limit} properties',
  bindings: { limit: 4 }
}

Error message of the { minProperties: 4 }:

{
  success: false,
  keyword: 'minProperties',
  description: 'Should not have fewer than {limit} properties',
  bindings: { limit: 4 }
}

required

The value of the keyword should be an array of unique strings. The data object to be valid should contain all properties with names equal to the elements in the keyword value.

Schema:

interface ISchema {
  required: string[]
}

Error message of the { required: ['foo', 'bar'] }:

{
  success: false,
  keyword: 'required',
  description: 'Should have all required properties',
  bindings: { invalidProperties: ['foo', 'bar'] }
}

properties

The value of the keyword should be a map with keys equal to data object properties. Each value in the map should be a JSON Schema. For data object to be valid the corresponding values in data object properties should be valid according to these schemas.

properties keyword does not require that the properties mentioned in it are present in the object

Schema:

interface ISchema {
  properties: { [propertyName: string]: Schema }
}

Error message of the { properties: { foo: { type: 'string' } } }:

{
  success: false,
  keyword: 'properties',
  description: 'Should have valid properties',
  bindings: { invalidProperties: ['foo'] }
}

additionalProperties

The value of the keyword should be either a boolean or a JSON Schema.

If the value is true the keyword is ignored.

If the value is false the data object to be valid should not have "additional properties" (i.e. properties other than those used in "properties" keyword).

If the value is a schema for the data object to be valid the values in all "additional properties" should be valid according to this schema.

Schema:

interface ISchema {
  additionalProperties: boolean | Schema
}

Error message of the { properties: { foo: { type: 'string' } }, additionalProperties: false }:

{
  success: false,
  keyword: 'properties',
  description: 'Should have valid properties',
  bindings: { invalidProperties: ['bar'] }
}

Compound keywords

not

The value of the keyword should be a JSON Schema. The data is valid if it is invalid according to this schema.The value of the keyword should be a JSON Schema. The data is valid if it is invalid according to this schema.

Schema:

interface ISchema {
  not: Schema
}

Error message of the { not: { type: 'string' } }:

{
  success: false,
  keyword: 'not',
  description: 'Should not be valid',
  bindings: {}
}

oneOf

The value of the keyword should be an array of JSON Schemas. The data is valid if it matches exactly one JSON Schema from this array. Validators have to validate data against all schemas to establish validity according to this keyword.

Schema:

interface ISchema {
  oneOf: Schema[]
}

Error message of the { oneOf: [{ type: 'string' }, { type: 'number' }] }:

{
  success: false,
  keyword: 'oneOf',
  description: 'Should match exactly one schema in oneOf',
  bindings: {}
}

anyOf

The value of the keyword should be an array of JSON Schemas. The data is valid if it is valid according to one or more JSON Schemas in this array. Validators only need to validate data against schemas in order until the first schema matches (or until all schemas have been tried)

Schema:

interface ISchema {
  anyOf: Schema[]
}

Error message of the { anyOf: [{ type: 'string' }, { type: 'number' }] }:

{
  success: false,
  keyword: 'anyOf',
  description: 'Should match some schema in anyOf',
  bindings: {}
}

allOf

The value of the keyword should be an array of JSON Schemas. The data is valid if it is valid according to all JSON Schemas in this array.

Schema:

interface ISchema {
  allOf: Schema[]
}

Error message of the { allOf: [{ type: 'integer' }, { type: 'number' }] }:

{
  success: false,
  keyword: 'allOf',
  description: 'Should match all schema in allOf',
  bindings: {}
}

if / then / else

These keywords allow you to implement conditional validation. Their values should be valid JSON Schemas.

Schema:

interface ISchema {
  if: Schema
  then: Schema
  else: Schema
}

applySchemas

Apply several validation schemas, useful when a property has several validation scenarios (for example if / then / else clauses)

Schema:

interface ISchema {
  applySchemas: Schema[]
}

Inline validation keywords

validate

Custom validation function receives current property ref and rule validation function being used for nested properties validation. The validation function must return a validation result object.

Schema:

type InlineFnValidationResult = ValidateFnResult
  | string
  | boolean
  | undefined

interface ISchema {
  validate: (ref: Ref) => InlineFnValidationResult | Promise<InlineFnValidationResult>
}

resolveSchema

Custom function receives the current property ref and returns a validation schema applicable to this property.

Schema:

interface ISchema {
  resolveSchema: (ref: Ref) => Schema | Promise<Schema>
}

Annotation keywords

readOnly

Marks property as read only.

Schema:

interface ISchema {
  readOnly: boolean
}

error / errors

These keywords are used to customize default error message descriptions if they are provided. The provided value will be used as the description of the error message instead of the default descriptions. error is used to customize any error message and takes precedence over warnings keyword, which is used to customize an error message of a particular keyword.

Schema:

interface ISchema {
  error: string
  errors: {
    // common
    type?: string
    const?: string
    enum?: string
    presence?: string
    // string
    format?: string
    pattern?: string
    minLength?: string
    maxLength?: string
    // number
    maximum?: string
    maximum_exclusive?: string
    minimum?: string
    minimum_exclusive?: string
    multipleOf?: string
    // array
    contains?: string
    minItems?: string
    maxItems?: string
    items?: string
    items_overflow?: string
    // object
    minProperties?: string
    maxProperties?: string
    properties?: string
    required?: string
    // conditionals
    allOf?: string
    anyOf?: string
    not?: string
    oneOf?: string
    // added custom keywords
    [keyword: string]: string
  }
}

warning / warnings

These keywords are used to customize default warning message descriptions if they are provided. The provided value will be used as the description of the warning message instead of the default descriptions. warning is used to customize any warning message and takes precedence over warnings keyword, which is used to customize a warning message of a particular keyword.

Schema:

interface ISchema {
  warning: any
  warnings: { [keyword: string]: any }  // default keywords don't expose warnings
}

Data mutation keywords

default

If property is undefined, provides default value for it

Schema:

interface ISchema {
  default: any
}

coerceTypes

If the keyword is true or the coerceTypes validation option is true - coerces data to the desired type if it needed. Coerce type rules:

  • to string: 123 => "123", true => "true", false => "false"
  • to number: false => 0, true => 1, null => 0, "123.45" => 123.45, not numeric strings "asd123" and empty strings "" are not being coerced.
  • to integer: false => 0, true => 1, null => 0, "123" => 123, not numeric strings "asd123", not integer strings "123.45" and empty strings "" are not being coerced.
  • to boolean: null => false, 0 => false, 1 => true
  • to null: "" => null, 0 => null, false => null

Schema:

interface ISchema {
  coerceTypes: boolean // default false
}

filter

The value of the keyword should be a function receiving a data value and returning filtered (normalized) value.

Schema:

interface ISchema {
  filter: (value: any) => any
}

removeAdditional

The value of the keyword should be a boolean.

When the keyword is true or the removeAdditional validation option is true:

  • if the value being validated is an object, the invalid properties (i.e. properties other than those used in "properties" keyword and those that do not satisfy "additionalProperties" keyword) are removed from the data object.
  • if the value being validated is an array, the invalid items (i.e. items other than those used in "items" keyword and those that do not satisfy "additionalItems" keyword) are removed from the data array.

Note that the validated value will be replaced with a cleaned value when the items or properties keyword finishes validation. So the following keywords will validate the cleaned value.

Schema:

interface ISchema {
  removeAdditional: boolean // default false
}

License

RJV is released under the MIT license. See the LICENSE file for license text and copyright information.