Валидация через format в Ajv применяется для проверки
строковых значений на соответствие заранее определённым шаблонам: email,
uri, дата, ip-адрес и другие. Механизм форматов изначально ориентирован
на синхронную проверку, что определяет его ключевое
ограничение при построении асинхронных схем.
Формат задаётся через ключ format в JSON Schema:
{
"type": "string",
"format": "email"
}
Внутри Ajv формат реализуется как функция, возвращающая булево значение:
ajv.addFormat('even-number', {
type: 'number',
validate: (data) => data % 2 === 0
});
Такая модель исключает возможность ожидания Promise или выполнения
асинхронных операций. Любая попытка сделать формат асинхронным нарушает
контракт синхронной валидации, на котором построен механизм
format.
Система форматов выполняется в процессе обхода дерева схемы. Этот процесс предполагает:
Асинхронность в этом контексте приводит к разрушению модели выполнения:
allErrors;По этой причине Ajv не допускает Promise в форматах, сохраняя их исключительно синхронными даже при использовании асинхронной валидации схем.
Для сценариев, где требуется обращение к внешним источникам или выполнение операций с задержкой, используется механизм кастомных ключевых слов.
Ключевое отличие от форматов заключается в том, что keyword может быть объявлен как асинхронный:
ajv.addKeyword({
keyword: 'isUniqueUser',
async: true,
type: 'string',
validate: async (schema, data) => {
const exists = await db.users.findByName(data);
return !exists;
}
});
Здесь validate возвращает Promise, а Ajv переключается в
режим асинхронной валидации всей схемы.
Такая модель делает возможным:
Для работы с асинхронными keyword используется специальный механизм компиляции:
const validate = ajv.compileAsync(schema);
validate(data)
.then(valid => {
// результат валидации
})
.catch(err => {
// ошибка валидации
});
Функция compileAsync отличается от обычной
compile тем, что анализирует схему и определяет наличие
асинхронных зависимостей.
Если схема содержит хотя бы один асинхронный keyword, весь валидатор становится Promise-based.
Асинхронная валидация в Ajv строится вокруг следующих принципов:
Пример структуры выполнения:
async function validate(data) {
if (!await keyword1(data)) return false;
if (!await keyword2(data)) return false;
return true;
}
Такой подход сохраняет совместимость с синхронной логикой, но расширяет её возможностью ожидания внешних операций.
Форматы и асинхронные keywords сосуществуют в одной системе, но имеют принципиально разные ограничения:
format всегда синхронен;keyword может быть как синхронным, так и
асинхронным;Если в схеме одновременно используется format и
асинхронный keyword, порядок выполнения сохраняется:
Асинхронные ключевые слова применяются в случаях, когда локальная проверка недостаточна:
Пример комбинированной схемы:
const schema = {
type: 'object',
properties: {
email: {
type: 'string',
format: 'email'
},
username: {
type: 'string',
isUniqueUser: true
}
}
};
В этом примере:
email выполняется синхронно;isUniqueUser инициирует асинхронный запрос;Асинхронная валидация формирует ошибки так же, как и синхронная, но с дополнительной стадией ожидания результата.
Структура ошибки включает:
instancePath);message);keyword);params).Пример обработки:
try {
await validate(data);
} catch (err) {
console.log(err.errors);
}
Ошибки агрегируются после завершения всех асинхронных операций, что позволяет получить полный набор нарушений.
Асинхронная валидация в Ajv имеет более высокую стоимость по сравнению с синхронной:
При проектировании схем важно учитывать:
Комбинированный подход позволяет использовать сильные стороны обеих моделей:
format обеспечивает быстрые локальные проверки;keyword async добавляет доступ к внешнему
состоянию.Такое разделение формирует двухуровневую систему валидации: