Граничные случаи валидации схем в Ajv проявляются в ситуациях, где данные формально соответствуют типу, но выходят за пределы ожидаемых значений, структуры или поведения JavaScript-движка. Такие сценарии критичны для надёжности API, поскольку именно на них чаще всего возникают скрытые ошибки и расхождения между спецификацией и реальной обработкой данных.
JavaScript использует формат IEEE 754 для чисел с плавающей точкой, что накладывает ограничения на точность и диапазон.
В контексте Ajv это приводит к нескольким типичным граничным случаям:
Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGERconst schema = {
type: "object",
properties: {
id: { type: "integer" }
},
required: ["id"]
};
Значения выше безопасного диапазона могут проходить проверку как числа, но терять точность ещё до валидации:
9007199254740993 === 9007199254740992 // true
Ajv опирается на уже преобразованное значение, поэтому схема не способна восстановить утраченные различия. Для строгой валидации больших идентификаторов применяется строковый тип с дополнительными ограничениями:
const schema = {
type: "object",
properties: {
id: {
type: "string",
pattern: "^[0-9]+$"
}
}
};
Строки в JSON-валидации часто содержат скрытые граничные случаи:
const schema = {
type: "object",
properties: {
username: {
type: "string",
minLength: 3,
maxLength: 20
}
}
};
Пустая строка ("") формально валидна как строка, но
нарушает бизнес-ограничения. Ajv не интерпретирует смысл данных, поэтому
проверка должна явно учитывать такие случаи через
minLength.
Особую сложность создают Unicode-символы:
lengthРазличие между отсутствием поля и значением null
является частым источником ошибок.
const schema = {
type: "object",
properties: {
title: { type: "string" }
},
required: ["title"]
};
Граничные случаи:
nullundefined (в JavaScript до
сериализации)Ajv различает:
required)null (ошибка типа, если не разрешён
null)Для поддержки null используется расширение:
const schema = {
type: "object",
properties: {
title: {
type: ["string", "null"]
}
}
};
Граничные случаи массивов включают:
const schema = {
type: "array",
items: { type: "number" },
minItems: 1,
maxItems: 5
};
Разреженные массивы ([1, , 3]) не всегда корректно
сериализуются в JSON, но при обработке в JavaScript могут появляться.
Ajv валидирует уже десериализованные данные, где такие элементы могут
отсутствовать как undefined, что приводит к неожиданным
результатам.
Комбинаторные конструкции часто создают неоднозначные граничные ситуации.
const schema = {
allOf: [
{ type: "object", properties: { a: { type: "number" } } },
{ type: "object", properties: { b: { type: "number" } } }
]
};
Граничный случай возникает при пересечении ограничений, которые
конфликтуют между собой, например разные type для одного
поля.
Наиболее проблемный случай — когда данные соответствуют более чем одной схеме:
oneOf: [
{ type: "number" },
{ type: "integer" }
]
Любое целое число соответствует обеим схемам, что приводит к провалу валидации.
При anyOf важен случай, когда данные формально проходят
хотя бы одну схему, но логически не соответствуют ожиданиям системы.
Ajv использует JavaScript RegExp, что создаёт следующие граничные ситуации:
const schema = {
type: "string",
pattern: "^(a+)+$"
};
Такие выражения могут приводить к резкому росту времени валидации при определённых входных данных.
const schema = {
type: "object",
additionalProperties: false
};
Граничные ситуации:
В JavaScript объект может содержать свойства из цепочки прототипов, что иногда приводит к ложным срабатываниям при неправильной настройке.
При включённой опции coerceTypes возникают крайние
случаи:
"0" → число 00 или NaNconst ajv = new Ajv({ coerceTypes: true });
Пограничное поведение:
" " (пробел) превращается в 0"true" не всегда интерпретируется как boolean"1e2" становится числом с плавающей точкойПри использовании useDefaults возникают ситуации,
где:
const schema = {
type: "object",
properties: {
count: {
type: "number",
default: 10
}
}
};
Граничный случай — различие между undefined и
отсутствием ключа, особенно при частичном обновлении данных.
Рекурсивные схемы создают особые крайние ситуации:
const node = {
type: "object",
properties: {
child: { $ref: "#" }
}
};
Циклические структуры требуют аккуратной настройки, иначе возможны бесконечные обходы при рекурсивной проверке.
При использовании асинхронных ключей (async validate)
возникают граничные состояния:
Особенно заметно при массовой валидации больших массивов объектов.
При включённом strict режиме Ajv начинает трактовать
неизвестные ключи как ошибку схемы.
Граничные случаи:
Небольшое изменение структуры может привести к полной невалидности схемы, хотя данные остаются корректными.
Ajv может возвращать несколько ошибок одновременно, но порядок их появления не гарантирован.
Граничные случаи:
allErrors: false)В таких ситуациях результат валидации становится недетерминированным по структуре массива ошибок, что требует аккуратной интерпретации на уровне приложения.