Another JSON Schema Validator - high-performance JSON Schema validator for JavaScript and TypeScript
npx @tessl/cli install tessl/npm-ajv@8.17.0Ajv (Another JSON Schema Validator) is a high-performance JSON Schema validator for JavaScript and TypeScript. It implements JSON Schema draft-04/06/07/2019-09/2020-12 standards and JSON Type Definition (JTD) RFC8927, generating optimized validation functions through code compilation for exceptional performance in Node.js and browsers.
npm install ajvimport Ajv from "ajv";
import type {
Schema,
ValidateFunction,
ErrorObject,
Options,
JSONSchemaType,
JTDSchemaType
} from "ajv";For specific JSON Schema versions:
import {Ajv2019} from "ajv/dist/2019.js";
import {Ajv2020} from "ajv/dist/2020.js";
import {Ajv as AjvJTD} from "ajv/dist/jtd.js";For standalone code generation:
import standaloneCode from "ajv/dist/standalone";For additional utilities:
import {ValidationError, MissingRefError} from "ajv";CommonJS:
const Ajv = require("ajv");
const {ValidationError, MissingRefError} = require("ajv");import Ajv from "ajv";
// Create validator instance
const ajv = new Ajv();
// Add schema
const schema = {
type: "object",
properties: {
foo: { type: "integer" },
bar: { type: "string" }
},
required: ["foo"],
additionalProperties: false
};
// Compile validation function
const validate = ajv.compile(schema);
// Validate data
const data = { foo: 1, bar: "abc" };
const valid = validate(data);
if (!valid) {
console.log(validate.errors);
}Ajv is built around several key components:
Primary JSON Schema validation functionality supporting Draft 7 schemas with discriminator support. Ideal for API validation, configuration validation, and data processing pipelines.
class Ajv extends AjvCore {
constructor(options?: Options);
errors?: ErrorObject[] | null;
validate<T>(schema: Schema | string, data: unknown): data is T;
validate(schemaKeyRef: AnySchema | string, data: unknown): boolean | Promise<unknown>;
compile<T>(schema: Schema, meta?: boolean): ValidateFunction<T>;
compileAsync<T>(schema: AnySchemaObject, meta?: boolean): Promise<AnyValidateFunction<T>>;
addSchema(schema: AnySchema | AnySchema[], key?: string, meta?: boolean, validateSchema?: boolean): Ajv;
addMetaSchema(schema: AnySchemaObject, key?: string, validateSchema?: boolean): Ajv;
removeSchema(schemaKeyRef?: AnySchema | string | RegExp): Ajv;
getSchema<T>(keyRef: string): AnyValidateFunction<T> | undefined;
validateSchema(schema: AnySchema, throwOrLogError?: boolean): boolean | Promise<unknown>;
addKeyword(kwdOrDef: string | KeywordDefinition, def?: KeywordDefinition): Ajv;
removeKeyword(keyword: string): Ajv;
getKeyword(keyword: string): AddedKeywordDefinition | boolean;
addVocabulary(definitions: Vocabulary): Ajv;
addFormat(name: string, format: Format): Ajv;
errorsText(errors?: ErrorObject[] | null, options?: ErrorsTextOptions): string;
}
type AnyValidateFunction<T = any> = ValidateFunction<T> | AsyncValidateFunction<T>;Enhanced validation for JSON Schema Draft 2019-09 with dynamic references, unevaluated properties/items, and next generation features.
class Ajv2019 extends AjvCore {
constructor(options?: Options);
validate<T>(schema: Schema, data: unknown): data is T;
compile<T>(schema: Schema): ValidateFunction<T>;
compileAsync<T>(schema: AnySchema, meta?: boolean): Promise<AnyValidateFunction<T>>;
}Latest JSON Schema Draft 2020-12 validation with all modern features and improvements.
class Ajv2020 extends AjvCore {
constructor(options?: Options);
validate<T>(schema: Schema, data: unknown): data is T;
compile<T>(schema: Schema): ValidateFunction<T>;
compileAsync<T>(schema: AnySchema, meta?: boolean): Promise<AnyValidateFunction<T>>;
}JTD schema validation with built-in serialization and parsing capabilities for high-performance data processing.
class Ajv extends AjvCore {
constructor(options?: JTDOptions);
validate<T>(schema: Schema, data: unknown): data is T;
compile<T>(schema: Schema): ValidateFunction<T>;
compileSerializer<T>(schema: SchemaObject): (data: T) => string;
compileParser<T>(schema: SchemaObject): JTDParser<T>;
}
interface JTDParser<T> {
(json: string): T | undefined;
message?: string;
position?: number;
}
type JTDOptions = CurrentOptions & {
strict?: never;
allowMatchingProperties?: never;
allowUnionTypes?: never;
validateFormats?: never;
$data?: never;
verbose?: boolean;
$comment?: never;
formats?: never;
loadSchema?: never;
useDefaults?: never;
coerceTypes?: never;
next?: never;
unevaluated?: never;
dynamicRef?: never;
meta?: boolean;
defaultMeta?: never;
inlineRefs?: boolean;
loopRequired?: never;
multipleOfPrecision?: never;
};Comprehensive schema management for adding, removing, and organizing schemas with support for references and meta-schemas.
interface SchemaManagement {
addSchema(schema: AnySchema | AnySchema[], key?: string, meta?: boolean, validateSchema?: boolean): Ajv;
addMetaSchema(schema: AnySchemaObject, key?: string, validateSchema?: boolean): Ajv;
removeSchema(schemaKeyRef?: AnySchema | string | RegExp): Ajv;
getSchema<T>(keyRef: string): AnyValidateFunction<T> | undefined;
validateSchema(schema: AnySchema, throwOrLogError?: boolean): boolean | Promise<unknown>;
}Extensible keyword system for creating custom validation logic, format validators, and vocabulary extensions.
interface KeywordSystem {
addKeyword(kwdOrDef: string | KeywordDefinition, def?: KeywordDefinition): Ajv;
removeKeyword(keyword: string): Ajv;
getKeyword(keyword: string): AddedKeywordDefinition | boolean;
addVocabulary(definitions: Vocabulary): Ajv;
addFormat(name: string, format: Format): Ajv;
}Advanced TypeScript integration with schema-to-type inference and compile-time type checking.
type JSONSchemaType<T> =
(T extends string ? {
type: "string";
enum?: readonly T[];
const?: T;
pattern?: string;
minLength?: number;
maxLength?: number;
format?: string;
} :
T extends number ? {
type: "number" | "integer";
enum?: readonly T[];
const?: T;
multipleOf?: number;
minimum?: number;
maximum?: number;
exclusiveMinimum?: number;
exclusiveMaximum?: number;
} :
T extends boolean ? {
type: "boolean";
const?: T;
} :
T extends readonly (infer U)[] ? {
type: "array";
items?: JSONSchemaType<U>;
minItems?: number;
maxItems?: number;
uniqueItems?: boolean;
contains?: JSONSchemaType<U>;
} :
T extends Record<string, any> ? {
type: "object";
properties?: {[K in keyof T]?: JSONSchemaType<T[K]>};
patternProperties?: Record<string, JSONSchemaType<any>>;
additionalProperties?: JSONSchemaType<any> | boolean;
required?: readonly (keyof T)[];
minProperties?: number;
maxProperties?: number;
dependencies?: {[K in keyof T]?: JSONSchemaType<any> | readonly string[]};
propertyNames?: JSONSchemaType<string>;
} :
T extends null ? {
type: "null";
const?: null;
} :
never) & {
$id?: string;
$schema?: string;
$ref?: string;
$comment?: string;
title?: string;
description?: string;
default?: T;
examples?: readonly T[];
nullable?: boolean;
discriminator?: {
propertyName: string;
mapping?: Record<string, string>;
};
readOnly?: boolean;
writeOnly?: boolean;
allOf?: readonly JSONSchemaType<T>[];
anyOf?: readonly JSONSchemaType<T>[];
oneOf?: readonly JSONSchemaType<T>[];
not?: JSONSchemaType<T>;
if?: JSONSchemaType<T>;
then?: JSONSchemaType<T>;
else?: JSONSchemaType<T>;
};
type JTDSchemaType<T, D = Record<string, never>> = (
| (T extends string
? { type: "string" }
: T extends number
? { type: "float64" | "float32" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" }
: T extends boolean
? { type: "boolean" }
: T extends readonly (infer U)[]
? U extends string
? { elements: { type: "string" } }
: U extends number
? { elements: { type: "float64" | "float32" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" } }
: U extends boolean
? { elements: { type: "boolean" } }
: { elements: JTDSchemaType<U, D> }
: T extends Record<string, any>
? {
properties: { [K in keyof T]: JTDSchemaType<T[K], D> };
} & ({
additionalProperties: true;
} | {
optionalProperties?: { [K in keyof T]?: JTDSchemaType<T[K], D> };
})
: never)
| { enum: readonly T[] }
| { ref: keyof D }
) & {
nullable?: boolean;
metadata?: Record<string, any>;
definitions?: { [K in keyof D]: JTDSchemaType<D[K], D> };
};
type SomeJTDSchemaType = JTDSchemaType<any, Record<string, any>>;
type JTDDataType<S> = S extends JTDSchemaType<infer T> ? T : never;Comprehensive error reporting system with detailed validation error information and customizable formatting.
interface ErrorObject<K extends string = string, P = Record<string, any>, S = unknown> {
keyword: K;
instancePath: string;
schemaPath: string;
params: P;
propertyName?: string;
message?: string;
schema?: S;
parentSchema?: AnySchemaObject;
data?: unknown;
}
type ErrorNoParams<K extends string, S = unknown> = ErrorObject<K, Record<string, never>, S>;
interface ErrorsTextOptions {
separator?: string;
dataVar?: string;
}
function errorsText(errors?: ErrorObject[] | null, options?: ErrorsTextOptions): string;
class ValidationError extends Error {
errors: ErrorObject[];
ajv: true;
validation: true;
constructor(errors: ErrorObject[]);
}
class MissingRefError extends Error {
readonly missingRef: string;
readonly missingSchema: string;
constructor(resolver: UriResolver, baseId: string, ref: string, msg?: string);
}Generate standalone validation functions that don't require the Ajv runtime for deployment optimization.
function standaloneCode(
ajv: Ajv,
refsOrFunc?: {[K in string]?: string} | AnyValidateFunction
): string;interface Options extends CurrentOptions, DeprecatedOptions {}
interface CurrentOptions {
// strict mode options
strict?: boolean | "log";
strictSchema?: boolean | "log";
strictNumbers?: boolean | "log";
strictTypes?: boolean | "log";
strictTuples?: boolean | "log";
strictRequired?: boolean | "log";
allowMatchingProperties?: boolean;
allowUnionTypes?: boolean;
validateFormats?: boolean;
// validation and reporting options
$data?: boolean;
allErrors?: boolean;
verbose?: boolean;
discriminator?: boolean;
unicodeRegExp?: boolean;
timestamp?: "string" | "date";
parseDate?: boolean;
allowDate?: boolean;
specialNumbers?: "fast" | "null";
$comment?: true | ((comment: string, schemaPath?: string, rootSchema?: AnySchemaObject) => unknown);
formats?: {[Name in string]?: Format};
keywords?: Vocabulary;
schemas?: AnySchema[] | {[Key in string]?: AnySchema};
logger?: Logger | false;
loadSchema?: (uri: string) => Promise<AnySchemaObject>;
// options to modify validated data
removeAdditional?: boolean | "all" | "failing";
useDefaults?: boolean | "empty";
coerceTypes?: boolean | "array";
// advanced options
next?: boolean;
unevaluated?: boolean;
dynamicRef?: boolean;
schemaId?: "id" | "$id";
jtd?: boolean;
meta?: SchemaObject | boolean;
defaultMeta?: string | AnySchemaObject;
validateSchema?: boolean | "log";
addUsedSchema?: boolean;
inlineRefs?: boolean | number;
passContext?: boolean;
loopRequired?: number;
loopEnum?: number;
ownProperties?: boolean;
multipleOfPrecision?: number;
int32range?: boolean;
messages?: boolean;
code?: CodeOptions;
uriResolver?: UriResolver;
}
interface DeprecatedOptions {
/** @deprecated */
ignoreKeywordsWithRef?: boolean;
/** @deprecated */
jsPropertySyntax?: boolean;
/** @deprecated */
unicode?: boolean;
}
interface CodeOptions {
es5?: boolean;
esm?: boolean;
lines?: boolean;
optimize?: boolean | number;
formats?: Code;
source?: boolean;
process?: (code: string, schema?: SchemaEnv) => string;
regExp?: RegExpEngine;
}
interface Logger {
log(...args: unknown[]): unknown;
warn(...args: unknown[]): unknown;
error(...args: unknown[]): unknown;
}
interface Plugin<Opts> {
(ajv: Ajv, options?: Opts): Ajv;
[prop: string]: any;
}type Schema = SchemaObject | boolean;
interface SchemaObject { $id?: string; $schema?: string; $ref?: string; $comment?: string;
// Type keywords type?: JSONType | JSONType[]; enum?: any[]; const?: any;
// Numeric keywords multipleOf?: number; maximum?: number; exclusiveMaximum?: number; minimum?: number; exclusiveMinimum?: number;
// String keywords maxLength?: number; minLength?: number; pattern?: string; format?: string;
// Array keywords items?: AnySchema | AnySchema[]; additionalItems?: AnySchema; maxItems?: number; minItems?: number; uniqueItems?: boolean; contains?: AnySchema;
// Object keywords maxProperties?: number; minProperties?: number; required?: string[]; additionalProperties?: AnySchema; properties?: {[key: string]: AnySchema}; patternProperties?: {[key: string]: AnySchema}; propertyNames?: AnySchema; dependencies?: {[key: string]: AnySchema | string[]};
// Boolean logic keywords allOf?: AnySchema[]; anyOf?: AnySchema[]; oneOf?: AnySchema[]; not?: AnySchema;
// Conditional keywords if?: AnySchema; then?: AnySchema; else?: AnySchema; }
type JSONType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
interface UriResolver { parse(uri: string): URIComponent; resolve(base: string, path: string): string; serialize(component: URIComponent): string; }
interface RegExpEngine { (pattern: string, u: string): RegExpLike; code: string; }
interface RegExpLike { test: (s: string) => boolean; }
type Format = AddedFormat | string;
type AddedFormat = | true | RegExp | FormatValidator<string> | FormatDefinition<string> | FormatDefinition<number> | AsyncFormatDefinition<string> | AsyncFormatDefinition<number>;
type FormatValidator<T extends string | number> = (data: T) => boolean;
interface FormatDefinition<T extends string | number> { type?: T extends string ? "string" | undefined : "number"; validate: FormatValidator<T> | (T extends string ? string | RegExp : never); async?: false | undefined; compare?: FormatCompare<T>; }
interface AsyncFormatDefinition<T extends string | number> { type?: T extends string ? "string" | undefined : "number"; validate: AsyncFormatValidator<T>; async: true; compare?: FormatCompare<T>; }
type AsyncFormatValidator<T extends string | number> = (data: T) => Promise<boolean>; type FormatCompare<T extends string | number> = (data1: T, data2: T) => number | undefined;
type Vocabulary = (KeywordDefinition | string)[];
interface KeywordDefinition { keyword: string | string[]; type?: JSONType | JSONType[]; schemaType?: JSONType | JSONType[]; allowUndefined?: boolean; $data?: boolean; implements?: string[]; before?: string; post?: boolean; metaSchema?: AnySchemaObject; validateSchema?: AnyValidateFunction; dependencies?: string[]; error?: KeywordErrorDefinition; $dataError?: KeywordErrorDefinition; }
type AddedKeywordDefinition = KeywordDefinition & { type: JSONType[]; schemaType: JSONType[]; };
interface KeywordErrorDefinition { message: string | ((cxt: KeywordErrorCxt) => string); params?: ((cxt: KeywordErrorCxt) => any); }
interface KeywordErrorCxt { gen: CodeGen; keyword: string; data: Name; $data?: string | false; schema: any; parentSchema?: AnySchemaObject; schemaCode: any; schemaValue: any; schemaType?: JSONType[]; errsCount?: Name; params: {[P in string]?: any}; it: SchemaCxt; }
type AnySchema = Schema | AsyncSchema; type AnySchemaObject = SchemaObject | AsyncSchema; type SchemaMap = {[Key in string]?: AnySchema};
interface AsyncSchema extends SchemaObject { $async: true; }
interface ValidateFunction<T = unknown> { (data: unknown): data is T; errors?: ErrorObject[] | null; evaluated?: Evaluated; schema: AnySchema; schemaEnv: SchemaEnv; source?: SourceCode; }
interface AsyncValidateFunction<T = unknown> extends ValidateFunction<T> { (data: unknown): Promise<T>; $async: true; }
type AnyValidateFunction<T = any> = ValidateFunction<T> | AsyncValidateFunction<T>;
interface Evaluated { props?: EvaluatedProperties; items?: EvaluatedItems; dynamicProps: boolean; dynamicItems: boolean; }
type EvaluatedProperties = {[K in string]?: true} | true; type EvaluatedItems = number | true;