API reference

Every export of schiva, with its options. The guide explains how to use them together; this page is the list to come back to. Everything is exported from schiva, with require and with import.

compileJsonSchema(json, options)

Compiles a JSON Schema (draft-04 to 2020-12) into a validation function. The function returns the errors of a value: [] when it is valid. What it returns depends on the compile options; the JSON Schema options choose how the schema is read. It throws when the schema is not supported (an unknown keyword, a reference that does not resolve...), with the place in the schema.

const validate = compileJsonSchema({ type: 'object', properties: { age: { type: 'integer', minimum: 0 } } });
validate({ age: -1 }); // ['age must be at least 0']

const isValid = compileJsonSchema(schema, { errors: false }); // (value) => true or false
const firstError = compileJsonSchema(schema, { allErrors: false }); // [] or [the first error]
const withObjects = compileJsonSchema(schema, { errors: 'objects' }); // error objects

In TypeScript, compileJsonSchema<T>(json, { errors: false }) is a type guard for T.

compileJsonSchemaAsync(json, options)

The same, for a schema that references documents to load first: a promise of the validation function. It calls options.loadSchema(uri), an async function you write, for each document the schema reaches and options.schemas does not have, and for the ones those reference in turn, once each. A reference relative to a schema without $id is not loaded; an error of loadSchema rejects the promise.

const validate = await compileJsonSchemaAsync(schema, {
  loadSchema: async (uri) => (await fetch(uri)).json(),
});

loadJsonSchemas(json, options)

Loads the same documents without compiling: a promise of options.schemas with them added, as { uri: schema }, to pass to compileJsonSchema() or standaloneJsonSchema() later.

fromJsonSchema(json, options)

Converts a JSON Schema into schiva types, with the same JSON Schema options, without compiling: the result has validate(value), isValid(value) and compile(options) like any type. compileJsonSchema(json, options) is compileType(fromJsonSchema(json, options), options).

type.compile(options) and compileType(type, options)

Compile a DSL schema or any type into a validation function, with the compile options: type.compile(options) and compileType(type, options) are the same. Compile once, when the program starts, and keep the function. Three older functions compile one mode each:

FunctionReturns a function givingSame as
compileIsValid(type)true or falsecompileType(type, { errors: false })
compileFirstError(type)the first message, or undefinedthe first element of { allErrors: false }
compileErrors(type)every messagecompileType(type)

Compile options

OptionValuesMeaning
allErrorstrue (default), falseevery error, or only the first one: the function stops at the first failing check, faster on invalid values
errorstrue (default), 'objects', falseerror messages (strings), error objects, or true/false with no errors built at all (the fastest)

JSON Schema options

For compileJsonSchema(), compileJsonSchemaAsync(), loadJsonSchemas(), fromJsonSchema() and standaloneJsonSchema(), next to the compile options:

OptionValuesMeaning
schemas{ uri: schema } or an array of schemas with $id (id in draft-04)documents that $ref can point to, and meta-schemas $schema can name (see Several documents)
draft'draft-04', 'draft-06', 'draft-07', '2019-09', '2020-12'the draft of the schema; by default the one $schema names, else draft-07
formatstrue, a list of built-in names, or { name: true | false | RegExp | function | { validate, compare } } (false: known, not checked); builtInFormats() gives every built-in onechecks format, an annotation without it; with strict, a format it does not name throws (see Formats and Formats of your own)
stricttrue (default), falsewith false, unknown keywords, keywords of other drafts and keywords a type excludes are ignored instead of throwing
keywordslist of names and definitionsnames are annotations of your own ('x-internal'); definitions are keywords that check values
useDefaultsfalse (default), true, 'empty'assigns the default of missing properties and tuple elements; 'empty' also replaces null and '' (see Changing the data)
removeAdditionalfalse (default), true, 'all', 'failing'removes additional properties: where additionalProperties is false; all of them; or the ones that fail additionalProperties
coerceTypesfalse (default), true, 'array'converts values to the types type asks for, with ajv's rules; 'array' also wraps and unwraps arrays
multipleOfPrecisiona positive integerdecimal digits: multipleOf accepts a division within 1e-n of an integer, so 0.3 is a multiple of 0.1
loadSchemaasync (uri) => schemafor compileJsonSchemaAsync() and loadJsonSchemas() only

standaloneJsonSchema, standaloneCode and standaloneModule

Write validators out as the source of a JavaScript module, to save to a file when building: loading it generates no code, so it runs under a strict Content Security Policy, and it needs nothing else, not even schiva. Each one takes the compile options, and format: 'commonjs' (default) or 'esm'.

FunctionModule
standaloneJsonSchema(json, options)the validator of a JSON Schema as its default export; takes the JSON Schema options too
standaloneCode(type, options)the validator of a type (a DSL schema, or the result of fromJsonSchema()) as its default export
standaloneModule({ name: type }, options)one named export for each entry, sharing the code they have in common
fs.writeFileSync('validate-order.js', standaloneJsonSchema(orderSchema, { format: 'esm', formats: true }));
fs.writeFileSync('validators.cjs', standaloneModule({ order, customer }, { errors: 'objects' }));

Everything the schema needs is written into the module: the built-in formats, error objects, defaults and the keywords that are macros or regular expressions. Functions of your own cannot be written out: types of your own, keywords with validate or compile, and formats given as functions throw a message naming them.

inferJsonSchema(samples, options) and inferSchemaCode(samples, options)

The schema of a list of sample values (a single value goes in a list), merged from all of them: a key is required when every object at that place has it, null makes a value nullable, integers and numbers make a number, array elements are merged, and strings get a format every one of them matches (see Schemas from samples, or try Schema from JSON). inferJsonSchema() returns a JSON Schema object; inferSchemaCode() returns the source of a module that builds the same schema with the DSL.

OptionValueMeaning
closedfalse (default) or trueobjects reject keys the samples do not have (additionalProperties: false, ClosedSchema)
formatstrue (default) or falsedetect date-time, date, time, email, uuid, ipv4, ipv6 and uri
draft'2020-12' (default), '2019-09', 'draft-07', 'draft-06', 'draft-04'the $schema written
name'schema' (default)inferSchemaCode() only: the name of the variable
module'commonjs' (default), 'esm', 'none'inferSchemaCode() only: the import line, with the names the code uses

Values that are not JSON (functions, Date objects, NaN) throw, naming where they are; keys whose value is undefined are taken as absent.

Common options and methods of the types

Every DSL type takes these options and has these methods:

Option or methodMeaning
isMandatorydefault true: undefined (a missing property) is an error, is mandatory
isNullabledefault false: null is an error, cannot be null
.optional(), .required()set isMandatory to false or true, and return the type
.nullable(), .notNull()set isNullable to true or false, and return the type
.mandatory(flag), .nullable(flag)the same with a value
.validate(value, fieldName)the errors without compiling: undefined, a message or a list (see validate() results)
.isValid(value)true or false without compiling
.compile(options)a validation function (see Compile options)

Wherever a type is expected, a plain object stands for new Schema(object) (an open schema). A value that is neither a type nor an object of types throws when the type is built.

new Schema(shape, options) and new ClosedSchema(shape, options)

A schema for objects: each key of shape is an expected property with its type. Declared keys are read as own properties only. ClosedSchema is a Schema with isOpen: false.

OptionMeaning
isOpendefault true; false rejects keys the shape does not declare: Unexpected key: extra
additionalTypetype of the keys the shape does not declare
patternTypes[{ pattern, type }]: type of the keys a regular expression matches; they are not additional keys
propertyNameTypetype every key must satisfy; its errors name the key Key name
minProperties, maxPropertiesnumber of keys
dependencies[{ key, required: [keys] }] or [{ key, type }]: when key is present, those keys must be too, or the whole object must satisfy type
isMandatory, isNullableas for every type
const config = new ClosedSchema(
  { name: String(), port: Integer({ min: 1, max: 65535 }), tls: Boolean().optional(), cert: String().optional() },
  { patternTypes: [{ pattern: /^x-/, type: Any() }], dependencies: [{ key: 'tls', required: ['cert'] }] }
);
config.compile()({ name: 'api', port: 443, tls: true, 'x-team': 'a', debug: true });
// ['Unexpected key: debug', 'cert is mandatory when tls is present']

String, Integer, Float and Boolean

TypeOptions
String(options)
StringType
min, max: length; pattern: a RegExp; format: a built-in format (email, date, uuid...); allowEmpty: whether '' passes min (by default, when the string is optional); countCodePoints: count lengths in Unicode code points instead of UTF-16 units (as JSON Schema does)
Integer(options), Float(options)
IntegerType, FloatType
min, max, exclusiveMin, exclusiveMax, multipleOf, multipleOfPrecision. Numbers must be finite: NaN and Infinity are not numbers
Boolean(options)
BooleanType
the common options

Enum, Values and Const

TypeAccepts
Enum({ options })
EnumType
one of the strings of options; takes the options of String too
Values({ values })
ValuesType
one of values, of any JSON type, compared deeply (objects and arrays by their content)
Const(value, options)that value only: Values({ values: [value], ...options })

ArrayOf(options)

OptionMeaning
typethe type of every element, or an array of types for the elements at each position (a tuple)
additionalTypewith a tuple, the type of the elements after it
min, maxnumber of elements
uniqueno two elements are equal (compared deeply)
contains, minContains, maxContainsat least one element (or between the two numbers) satisfies contains
ArrayOf({ type: [String(), Integer()], additionalType: Boolean(), min: 2 }); // ['a', 1, true, false]

AnyOf, AllOf, OneOf and Not

TypeAccepts
AnyOf({ types })values at least one of the types accepts; otherwise the errors of every type
AllOf({ types })values every type accepts; the errors of each one
OneOf({ types })values exactly one of the types accepts
Not({ type })values the type rejects: must not match the excluded schema

Conditional and When

TypeAccepts
Conditional({ ifType, thenType, elseType })when the value satisfies ifType, it must satisfy thenType, else elseType (JSON Schema's if/then/else); either may be left out
When({ jsonType, type })checks type only for values of that JSON type ('object', 'array', 'string', 'number'); other values pass. isJsonType(value, jsonType) is its test
Conditional({
  ifType: { country: Const('US') },
  thenType: { zip: String({ pattern: /^\d{5}$/ }) },
  elseType: { zip: String() },
});

Any, Never, Obj and Ref

TypeAccepts
Any(options)every value (with the presence options)
Never(options)no value: is not allowed; with isMandatory: false (the default of never()), a missing property passes
Obj({ schema })any object, or one a schema accepts
Ref({ target })what target accepts; set ref.target later for recursive schemas (see Recursive schemas)

Short helpers

Functions with positional arguments, for short schemas. Each has an optional version starting with o (isMandatory defaults to false).

HelperSame as
str(min, max, isMandatory, isNullable), ostrString({ min, max, ... })
int(min, max, ...), ointInteger({ min, max, ... })
float(min, max, ...), ofloat, num, onumFloat({ min, max, ... })
bool(isMandatory, isNullable), oboolBoolean()
any(), oany, never()Any(), Never()
enumt(options, ...), oenumt, oenumEnum({ options })
arrOf(type, min, max, ...), oarrOfArrayOf({ type, min, max }); arrOf({ type, min, ... }) takes the options
obj(shape, ...), oobjObj({ schema: shape }); obj({ schema, isNullable, ... }) takes the options
anyOf(types), allOf, oneOf, and oanyOf, oallOf, ooneOfAnyOf({ types })...
not(type), onotNot({ type })

ValidateType

The base class of every type. Extend it (or a built-in type) with your own validate(value, fieldName) returning undefined or a message, and optionally a faster isValid(value); the compiled code calls them for their part of a schema. super.validate(value, fieldName) checks isMandatory and isNullable. checkPresence(value) gives the verdict for undefined and null (undefined for other values). See Types of your own.

Keyword definitions

Items of the JSON Schema option keywords that check values:

PropertyMeaning
keywordits name; not a keyword of JSON Schema
typeJSON types of the values it checks ('string', 'number', 'integer', 'boolean', 'object', 'array', 'null'), one or a list; every value by default. A macro takes object, array, string or number
validate(value, data, parentSchema)called for each value with the value of the keyword: true when valid
compile(value, parentSchema, { draft })called once, when compiling: gives the function checking the data, or a regular expression the data must match
macro(value, parentSchema, { draft })gives a schema to check instead; compiles to the same code as its keywords
messagethe text of its error after the name of the value, or (value, data) => text; must pass the "<keyword>" keyword by default. A function with one parameter is called once, when compiling

A definition has exactly one of validate, compile and macro. Compiled, a keyword becomes a KeywordType ({ keyword, check, message, jsonTypes }), which can also be used in the DSL.

ajvKeywords(names)

Definitions of the keywords of ajv-keywords, with the same results: all of them, or the ones named (a name or a list). transform, dynamicDefaults and select throw, with the reason.

KeywordValueChecksStandalone
typeofa name or namesthe typeof of the valueno
instanceof'Date', 'RegExp', 'Map'... or a listthe class of the valueno
range, exclusiveRange[min, max]numbers between the two, included or notyes
regexp'/pattern/flags' or { pattern, flags }strings the regular expression matchesyes, without the flags g and y
uniqueItemPropertiesproperty namesno two elements have equal values of each oneno
allRequiredtrueevery key of properties is presentyes
anyRequired, oneRequiredproperty namesat least one, or exactly one, is presentyes
patternRequiredpatternsfor each one, a key matches itno
prohibitedproperty namesnone of them is present: x is not allowedyes
deepProperties{ '/json/pointer': schema }the values at those pointersyes
deepRequiredJSON pointersthe values at those pointers are definedno

Formats of your own

In the JSON Schema option formats, a name maps to true (a built-in format), false (a format that is known but not checked, as OpenAPI's int32), a regular expression, a function (string) => boolean, or { validate, compare }, whose compare(a, b) gives a negative number, 0 or a positive number, so that formatMinimum, formatMaximum, formatExclusiveMinimum and formatExclusiveMaximum can limit its values.

compileJsonSchema(schema, {
  formats: {
    date: true,
    sku: /^SKU-\d+$/,
    version: { validate: /^\d+\.\d+$/, compare: (a, b) => a.localeCompare(b, 'en', { numeric: true }) },
  },
});

builtInFormats() gives every built-in format as { date: true, ... }, to check them all and add others: formats: { ...builtInFormats(), int32: false, sku: /^SKU-\d+$/ }. With strict (the default), a format the option does not name throws when compiling.

validate() results, toErrors and hasErrors

type.validate(value) (without compiling) returns undefined when the value is valid, a message, or a list that may nest lists (combinations collect the errors of their parts). toErrors(result) gives its messages as a flat list, each once, as the compiled function gives them; hasErrors(result) tells whether it has any.

toErrors(schema.validate(value)); // ['name is mandatory', ...]
hasErrors(schema.validate(value)); // true

Error objects

With errors: 'objects', each error is an object:

PropertyMeaning
paththe keys and indexes of the value: ['lines', 0, 'price'], [] for the value itself
pointerthe same path as a JSON Pointer: '/lines/0/price'
keywordthe check that failed (see Messages and keywords)
paramsits details, {} when there are none
messagethe message of the default mode
propertyNametrue for an error of a key checked by propertyNames, whose path is the one of its property

Messages and keywords

Every message starts with the name of the value (lines[0].price, or Value for the value itself). The keyword and params are the ones of error objects.

Message after the namekeywordparams
is mandatoryrequired{}
cannot be nullnullable{}
must be a string, a number, an integer, a boolean, an object, an arraytype{ type }
must be at least N characters long, at most N characters longminLength, maxLength{ limit }
does not match the required patternpattern{ pattern }
must be a valid FORMATformat{ format }
must be at least N, at most N, greater than N, less than Nminimum, maximum, exclusiveMinimum, exclusiveMaximum{ limit }
must be a multiple of NmultipleOf{ multipleOf }
must be at least, at most, greater than, less than LIMIT (a format)formatMinimum, formatMaximum, formatExclusiveMinimum, formatExclusiveMaximum{ comparison, limit }
must be one of: A, Benum{ allowedValues }
must be equal to Aconst{ allowedValue }
must have at least N elements, at most N elementsminItems, maxItems{ limit }
must not have duplicate elementsuniqueItems{}
must contain at least one matching elementcontains{}
must contain at least N matching elements, at most N matching elementsminContains, maxContains{ limit }
must have at least N properties, at most N propertiesminProperties, maxProperties{ limit }
(the whole message) Unexpected key: NAMEadditionalProperties, unevaluatedProperties{ property }
is mandatory when KEY is presentdependentRequired{ property, missingProperty }
is not allowedfalse{}
must not match the excluded schemanot{}
must match exactly one schema, but matches none (or more than one)oneOf{ passing }
TAG is mandatory, must be a string, must be one of: A, Bdiscriminator{ error, tag, tagValue }
the message of a keyword of your ownits name{}
the message of a type of your owncustom{}

TypeScript types

TypeMeaning
Infer<typeof schema>the type of the values a DSL schema accepts
ErrorsFunction, ErrorObjectsFunction, IsValidFunction<T>the compiled functions of each mode; the last one is a type guard
ErrorObjectan error object
CompileOptions, JsonSchemaOptions, StandaloneOptions, LoadSchemaOptionsthe options above
JsonSchema, JsonSchemaObject, JsonSchemaDrafta JSON Schema, and the names of the drafts
KeywordDefinition, AjvKeywordName, FormatDefinition, FormatName, FormatCheckkeywords and formats of your own, and the built-in names
ValidationResultwhat validate() returns
StringOptions, NumberOptions, ArrayOfOptions, SchemaOptions...the options of each type