Валидация пользовательского ввода — один из ключевых этапов построения надёжных JavaScript-приложений, особенно в серверной разработке и API. Она позволяет гарантировать, что входящие данные соответствуют ожидаемой структуре, типам и ограничениям, предотвращая ошибки выполнения, неконсистентность данных и потенциальные уязвимости.
Библиотека Ajv реализует проверку данных на основе спецификации JSON Schema и считается одной из самых быстрых и функциональных реализаций в экосистеме JavaScript. Её использование особенно актуально в системах, где требуется строгая типизация входных данных при сохранении динамичности языка.
В основе Ajv лежит идея декларативного описания структуры данных. Вместо написания процедурных проверок используется схема, описывающая допустимые значения.
Пример простой схемы:
const schema = {
type: "object",
properties: {
username: { type: "string" },
age: { type: "integer", minimum: 0 }
},
required: ["username", "age"],
additionalProperties: false
};
Такая схема описывает объект, который обязан содержать строковое поле
username и целочисленное поле age, причём
возраст не может быть отрицательным.
Создание экземпляра валидатора и проверка данных:
import Ajv from "ajv";
const ajv = new Ajv();
const validate = ajv.compile(schema);
const data = {
username: "user1",
age: 25
};
const valid = validate(data);
if (!valid) {
console.log(validate.errors);
}
Метод compile преобразует схему в оптимизированную
функцию проверки. Это важная особенность Ajv: схема компилируется один
раз, после чего валидация выполняется максимально быстро.
Ajv строго опирается на типы JSON Schema:
Пример более сложной типизации:
const schema = {
type: "object",
properties: {
id: { type: "integer" },
email: { type: "string", format: "email" },
isActive: { type: "boolean" }
},
required: ["id", "email"]
};
Ключевую роль играет управление обязательными свойствами:
required: ["id", "email"]
Если поле отсутствует, валидация завершится ошибкой.
Запрет дополнительных свойств:
additionalProperties: false
Это особенно важно для API, где необходимо жёстко контролировать входящий контракт данных.
Ajv позволяет детально описывать структуру массивов:
const schema = {
type: "object",
properties: {
tags: {
type: "array",
items: { type: "string" },
minItems: 1,
uniqueItems: true
}
}
};
Здесь массив tags должен содержать только строки,
минимум один элемент и не допускать дубликатов.
Одно из наиболее распространённых применений — валидация вложенных объектов:
const schema = {
type: "object",
properties: {
user: {
type: "object",
properties: {
name: { type: "string" },
profile: {
type: "object",
properties: {
age: { type: "integer" },
city: { type: "string" }
},
required: ["age"]
}
},
required: ["name", "profile"]
}
}
};
Такая структура часто используется в REST API и GraphQL входных данных.
Ajv поддерживает проверку форматов:
Пример:
email: { type: "string", format: "email" }
Форматы требуют подключения соответствующих опций или плагинов в зависимости от конфигурации.
Ajv может автоматически приводить типы:
const ajv = new Ajv({ coerceTypes: true });
Пример: строка "25" может быть преобразована в число
25. Это полезно при обработке данных из HTTP-запросов, где
всё приходит в виде строк.
Строгая проверка помогает выявлять ошибки в схемах:
const ajv = new Ajv({ strict: true });
В строгом режиме библиотека предупреждает о:
Ajv возвращает массив ошибок:
if (!valid) {
console.log(validate.errors);
}
Структура ошибки:
Пример обработки:
validate.errors.forEach(err => {
console.log(`${err.instancePath} ${err.message}`);
});
Ajv позволяет расширять систему валидации:
ajv.addKeyword({
keyword: "isEven",
validate: function (schema, data) {
return typeof data === "number" && data % 2 === 0;
}
});
Использование:
const schema = {
type: "object",
properties: {
value: { isEven: true }
}
};
Ajv поддерживает асинхронные проверки, например обращение к базе данных:
const schema = {
type: "object",
properties: {
username: {
type: "string",
async: true,
validate: async (value) => {
const exists = await checkUser(value);
return !exists;
}
}
}
};
Для этого требуется использование compileAsync.
Схемы можно переиспользовать:
const addressSchema = {
type: "object",
properties: {
city: { type: "string" },
zip: { type: "string" }
}
};
const userSchema = {
type: "object",
properties: {
name: { type: "string" },
address: addressSchema
}
};
Это снижает дублирование и улучшает поддержку кода.
Ajv поддерживает сложные условия:
const schema = {
type: "object",
properties: {
role: { type: "string" }
},
if: {
properties: { role: { const: "admin" } }
},
then: {
required: ["permissions"]
}
};
Такая конструкция позволяет описывать бизнес-логику на уровне схемы.
В серверной разработке результат Ajv обычно преобразуется в стандартизированный формат:
const errors = validate.errors.map(err => ({
field: err.instancePath,
message: err.message
}));
Это позволяет возвращать клиенту структурированный ответ:
{
"errors": [
{
"field": "/age",
"message": "should be >= 0"
}
]
}
Ajv оптимизирован для высоконагруженных систем:
Рекомендуется:
Использование схемы позволяет:
Особенно важно сочетание:
additionalProperties: false
и строгих типов, что формирует предсказуемый контракт данных.
Типичные сценарии применения: