Ajv поддерживает систему расширений, позволяющую адаптировать валидатор под требования проекта: добавлять собственные ключевые слова, форматы, трансформации данных, интеграцию с TypeScript и генерацию ошибок.
Механизм расширения строится вокруг нескольких направлений:
addKeyword)addFormat)ajv-formats, ajv-errors,
ajv-keywords)Базовый экземпляр Ajv:
const Ajv = require("ajv")
const ajv = new Ajv({
allErrors: true,
strict: true
})
Большинство расширений устанавливается отдельно.
npm install ajv
npm install ajv-formats
npm install ajv-keywords
npm install ajv-errors
const Ajv = require("ajv")
const addFormats = require("ajv-formats")
const addKeywords = require("ajv-keywords")
const ajv = new Ajv()
addFormats(ajv)
addKeywords(ajv)
Плагин получает экземпляр Ajv и модифицирует его внутренний реестр.
В стандарт JSON Schema входят форматы:
emailuridateipv4uuidОднако Ajv v7+ вынес их в отдельный пакет.
Без подключения ajv-formats проверка format
не выполняется.
const schema = {
type: "string",
format: "email"
}
const validate = ajv.compile(schema)
console.log(validate("admin@example.com"))
console.log(validate("wrong-email"))
const schema = {
type: "string",
format: "uri"
}
const schema = {
type: "string",
format: "uuid"
}
const schema = {
type: "string",
format: "date"
}
Формат соответствует ISO 8601:
2025-05-10
const ajv = new Ajv({
validateFormats: true
})
const ajv = new Ajv({
validateFormats: false
})
ajv-formats добавляет поддержку:
formatMinimumformatMaximumformatExclusiveMinimumformatExclusiveMaximumПример:
const schema = {
type: "string",
format: "date",
formatMinimum: "2024-01-01"
}
Ajv позволяет создавать собственные форматы.
ajv.addFormat("hex-color", {
type: "string",
validate: (value) => {
return /^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(value)
}
})
Использование:
const schema = {
type: "string",
format: "hex-color"
}
Формат может работать с number.
ajv.addFormat("positive-number", {
type: "number",
validate: (value) => value > 0
})
Упрощённый вариант:
ajv.addFormat("slug", /^[a-z0-9-]+$/)
ajv-keywords добавляет множество дополнительных ключевых слов JSON Schema.
Среди них:
transformuniqueItemPropertiesinstanceofregexpdeepRequireddynamicDefaultsselectrangeПозволяет изменять строку перед валидацией.
const schema = {
type: "string",
transform: ["trim"]
}
const schema = {
type: "string",
transform: ["trim", "toLowerCase"]
}
Проверка уникальности свойства в массиве объектов.
const schema = {
type: "array",
uniqueItemProperties: ["id"]
}
Данные:
[
{ id: 1 },
{ id: 2 }
]
Проверка экземпляра класса.
const schema = {
instanceof: "Date"
}
Расширенная работа с регулярными выражениями.
const schema = {
type: "string",
regexp: "/^[A-Z]+$/"
}
Проверка вложенных полей.
const schema = {
deepRequired: ["/user/profile/name"]
}
Альтернатива minimum и maximum.
const schema = {
type: "number",
range: [1, 10]
}
ajv-errors позволяет задавать собственные сообщения об ошибках.
const Ajv = require("ajv")
const ajvErrors = require("ajv-errors")
const ajv = new Ajv({
allErrors: true
})
ajvErrors(ajv)
const schema = {
type: "object",
required: ["email"],
properties: {
email: {
type: "string",
format: "email"
}
},
errorMessage: {
required: {
email: "Поле email обязательно"
},
properties: {
email: "Некорректный email"
}
}
}
errorMessage: "Данные не прошли валидацию"
errorMessage: {
properties: {
age: "Возраст указан неверно"
}
}
Главный механизм расширения Ajv.
ajv.addKeyword({
keyword: "even",
type: "number",
validate(schema, data) {
return data % 2 === 0
}
})
Схема:
const schema = {
type: "number",
even: true
}
Основные поля:
| Поле | Назначение |
|---|---|
keyword |
имя keyword |
type |
тип данных |
schemaType |
тип значения keyword |
validate |
функция проверки |
compile |
генератор валидатора |
code |
генерация кода |
metaSchema |
схема keyword |
errors |
поддержка ошибок |
ajv.addKeyword({
keyword: "isPrime",
type: "number",
validate(schema, data) {
if (!schema) return true
for (let i = 2; i < data; i++) {
if (data % i === 0) return false
}
return data > 1
}
})
const schema = {
type: "number",
isPrime: true
}
compile вызывается один раз при создании валидатора.
ajv.addKeyword({
keyword: "startsWith",
compile(prefix) {
return function (data) {
return data.startsWith(prefix)
}
}
})
Ajv генерирует оптимизированный JS-код валидатора.
Пользовательские keywords могут участвовать в генерации.
ajv.addKeyword({
keyword: "positive",
code(cxt) {
const { data } = cxt
cxt.fail(`${data} <= 0`)
}
})
Подход validate вызывает функции во время
выполнения.
Подход code генерирует итоговый JS-валидатор без
дополнительных вызовов.
Keyword может преобразовываться в другую JSON Schema.
ajv.addKeyword({
keyword: "nonEmptyString",
macro() {
return {
type: "string",
minLength: 1
}
}
})
Использование:
const schema = {
nonEmptyString: true
}
Ajv поддерживает Promise-based validation.
ajv.addKeyword({
keyword: "userExists",
async: true,
validate: async function (schema, data) {
const user = await db.findUser(data)
return !!user
}
})
const schema = {
$async: true,
type: "string",
userExists: true
}
try {
await validate("admin")
} catch (err) {
console.log(err.errors)
}
ajv.addKeyword({
keyword: "even",
errors: true,
validate(schema, data) {
const valid = data % 2 === 0
if (!valid) {
this.errors = [
{
keyword: "even",
message: "число должно быть чётным"
}
]
}
return valid
}
})
metaSchema определяет структуру самого keyword.
ajv.addKeyword({
keyword: "range",
metaSchema: {
type: "array",
items: { type: "number" },
minItems: 2,
maxItems: 2
}
})
Keyword может объявлять зависимость.
ajv.addKeyword({
keyword: "range",
implements: ["exclusiveRange"]
})
Keyword может мутировать входные данные.
ajv.addKeyword({
keyword: "appendX",
modifying: true,
validate(schema, data, parentSchema, ctx) {
ctx.parentData[ctx.parentDataProperty] += "X"
return true
}
})
ajv.addKeyword({
keyword: "positive",
inline() {
return "(data > 0)"
}
})
Подход использовался в старых версиях Ajv и постепенно заменяется
code.
Ajv позволяет добавлять собственные стандарты схем.
ajv.addMetaSchema({
$id: "custom-schema",
type: "object",
properties: {
type: {
type: "string"
}
}
})
Можно регистрировать наборы keyword одновременно.
ajv.addVocabulary([
"range",
"positive",
"nonEmptyString"
])
ajv-i18n переводит ошибки Ajv.
npm install ajv-i18n
const localize = require("ajv-i18n")
localize.ru(validate.errors)
После локализации:
console.log(validate.errors)
ajv-cli предоставляет командную строку для проверки JSON.
npm install -g ajv-cli
ajv validate -s schema.json -d data.json
ajv validate -s schema.json -d "data/*.json"
Ajv умеет генерировать автономные валидаторы без runtime Ajv.
const standaloneCode = require("ajv/dist/standalone")
const moduleCode = standaloneCode(ajv, validate)
import Ajv, { KeywordDefinition } from "ajv"
const keyword: KeywordDefinition = {
keyword: "positive",
type: "number",
validate(schema: boolean, data: number) {
return data > 0
}
}
Типобезопасные схемы:
interface User {
name: string
age: number
}
const schema: JSONSchemaType<User> = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "number" }
},
required: ["name", "age"],
additionalProperties: false
}
module.exports = function (ajv) {
ajv.addKeyword({
keyword: "positive",
validate(schema, data) {
return data > 0
}
})
return ajv
}
const positivePlugin = require("./positive-plugin")
positivePlugin(ajv)
function setupAjv(ajv) {
addFormats(ajv)
addKeywords(ajv)
ajvErrors(ajv)
return ajv
}
| Подход | Скорость |
|---|---|
validate |
ниже |
compile |
выше |
code |
максимальная |
Особенно затратны:
// validation/index.js
module.exports = function createAjv() {
const ajv = new Ajv({
allErrors: true
})
addFormats(ajv)
addKeywords(ajv)
return ajv
}
// validation/keywords/index.js
module.exports = function (ajv) {
require("./positive")(ajv)
require("./range")(ajv)
require("./slug")(ajv)
}
Лучше:
{
type: "string",
minLength: 3
}
Чем:
{
customValidation: true
}
Изменение входных данных усложняет отладку и делает поведение неявным.
metaSchema предотвращает ошибки конфигурации на этапе
компиляции схемы.
Сложные вычисления лучше переносить в:
compilecodeДля production-систем с высокой нагрузкой standalone validators существенно уменьшают накладные расходы.