Валидация строк в схемах Joi часто требует предварительной очистки пользовательского ввода. Одной из базовых операций является удаление пробелов в начале и конце строки.
В Joi это реализуется через метод trim():
const schema = Joi.string().trim();
При использовании данного метода строка автоматически нормализуется:
Пример поведения:
const schema = Joi.string().trim();
schema.validate(" hello world ");
// результат: "hello world"
Важно учитывать, что trim() применяется после
базовой проверки типа, но до финальной выдачи результата. Это
означает, что валидация длины (min, max) будет
происходить уже на очищенной строке.
const schema = Joi.string().trim().min(5);
schema.validate(" hi ");
// после trim -> "hi"
// длина = 2 → ошибка min(5)
При необходимости можно комбинировать trim() с другими
строковыми преобразованиями:
const schema = Joi.string()
.trim()
.lowercase()
.min(3);
Unicode-строки могут иметь разные формы представления одного и того
же символа. Например, символ «é» может быть записан как единый код или
как комбинация e + акцент.
Для унификации используется метод normalize().
В Joi он применяется следующим образом:
const schema = Joi.string().normalize();
По умолчанию используется форма NFC (Normalization Form
Canonical Composition).
Метод normalize() поддерживает стандартные формы
Unicode:
Пример явного указания формы:
const schema = Joi.string().normalize('NFKC');
Нормализация используется для устранения скрытых различий в строках, которые визуально идентичны, но отличаются внутренним представлением.
Типичные проблемы без нормализации:
Пример:
const schema = Joi.string().normalize('NFC');
schema.validate("e\u0301"); // "é"
schema.validate("\u00e9"); // "é"
После нормализации оба варианта приводятся к единому виду.
В реальных схемах очистка строки часто требует комбинации операций:
const schema = Joi.string()
.trim()
.normalize('NFC');
Порядок операций имеет значение:
trim() удаляет внешние пробелы;normalize() приводит строку к единой
Unicode-форме.Такой подход обеспечивает предсказуемое поведение при сравнении и хранении данных.
Оба метода являются частью этапа преобразования значения. Это
означает, что итоговое значение, возвращаемое после
validate, уже будет изменено.
const schema = Joi.string().trim().normalize();
const { value } = schema.validate(" café\u0301 ");
// value: "café́" (в нормализованной форме без внешних пробелов)
Это особенно важно при работе с:
Методы trim() и normalize() не изменяют
семантику строки, а только её представление.
Не обрабатываются:
lowercase() или
uppercase());Также следует учитывать, что normalize() может
увеличивать или уменьшать длину строки, что влияет на правила
min() и max().
const schema = Joi.string()
.normalize('NFKD')
.max(10);
В таком случае проверка длины выполняется уже после преобразования.
Методы очистки часто используются вместе с другими встроенными трансформациями:
const schema = Joi.string()
.trim()
.normalize()
.lowercase()
.replace(/\s+/g, ' ');
Такая цепочка обеспечивает:
После применения trim() строка может стать пустой:
Joi.string().trim().min(1);
Строка " " после обработки превращается в
"", что приводит к ошибке валидации при
min(1).
При использовании Joi в слоях валидации API важно учитывать, что
trim() и normalize() изменяют фактическое
значение.
Это влияет на:
Одинаковые визуально строки после нормализации становятся полностью идентичными на уровне байтового представления.
При использовании custom() важно учитывать, что входное
значение уже изменено:
const schema = Joi.string()
.trim()
.normalize()
.custom((value) => {
return value.startsWith('A') ? value : null;
});
Кастомная функция получает уже очищенную и нормализованную строку, а не исходный ввод.
Внутренний порядок обработки строки в Joi можно представить так:
string);trim, normalize,
lowercase и др.);custom);min, max,
pattern);Такой порядок делает поведение предсказуемым и позволяет строить строгие схемы валидации с контролируемой очисткой входных данных.