Урок курса
Чистые данные: нормализация и валидация
n8n с нуля: автоматизация заявок с AI за вечерФорма настроена, тестовая отправка работает. Но данные, которые приходят из формы, — сырые: пользователь мог написать имя с пробелами, email заглавными буквами или оставить поле пустым. Перед тем как передавать эти данные дальше по цепочке, их нужно привести к единому виду — иначе любая последующая проверка или поиск по значению будет ненадёжной.
Нормализация строковых полей через Edit Fields
Нормализация — это приведение значений к единообразному виду до того, как они попадут в любую следующую логику. Без неё два item с "Алексей" и " алексей " будут выглядеть как разные значения, хотя содержат одно и то же имя. В n8n нормализация строк делается прямо внутри узла Edit Fields через expression. Никаких дополнительных узлов не нужно — достаточно вписать JavaScript-выражение в поле значения.
Три метода, которые покрывают большинство случаев:
.trim()— убирает пробелы в начале и конце строки. Пользователи часто случайно добавляют их при вводе..toLowerCase()/.toUpperCase()— унифицирует регистр. Особенно важно для email:User@Mail.comиuser@mail.com— одно и то же, но без нормализации они не совпадут..replace()— заменяет нежелательные символы. Например,.replace(/\s+/g, ' ')сжимает несколько пробелов подряд в один.
Методы можно объединять в цепочку: каждый следующий применяется к результату предыдущего. В итоге " User@Mail.COM " превращается в "user@mail.com" одним выражением:
{{ $json['Email'].trim().toLowerCase() }}
Однако у этой записи есть ограничение: она предполагает, что ключ Email в JSON item существует. Если поле не было заполнено и ключ отсутствует, $json['Email'] вернёт undefined — и .trim() вызовет ошибку выполнения. Поэтому в реальном workflow используют тернарный оператор:
{{ $json['Email'] ? $json['Email'].trim().toLowerCase() : '' }}
Логика: если значение существует — применяем преобразование, иначе подставляем пустую строку. Для поля имени аналогично:
{{ $json['Имя'] ? $json['Имя'].trim() : '' }}
Подробнее о том, почему отсутствующий ключ вызывает ошибку и как с этим работать, разберём в разделе про Stop and Error.
В Edit Fields для каждого поля нужно переключиться в режим Expression и прописать преобразование. После сохранения узла проверьте панель Output — там должны быть уже приведённые значения: без лишних пробелов, email строчными буквами. Если expression написан с ошибкой, узел окрасится в красный прямо здесь, до IF.
Нормализация — это первый узел после Form Trigger. Она не проверяет, заполнены ли поля — только приводит значения к нужному виду. Проверка наличия обязательных данных — следующий шаг, который делает узел IF.
Валидация обязательных полей узлом IF
После того как Edit Fields привёл значения к нужному виду, нужно ответить на вопрос: а есть ли там вообще что-то полезное? Именно для этого к цепочке подключается узел IF.
IF работает просто: он проверяет заданное условие для каждого item и отправляет его в одну из двух веток — true или false. В контексте валидации удобнее мыслить от обратного: условие описывает проблему, а не норму.
Если условие формулируется как «поле пустое», то:
- ветка true — данные невалидны, item нужно остановить;
- ветка false — данные в порядке, обработка продолжается дальше.
Простейшее условие для проверки email выглядит так:
{{ $json.email === '' }}
Но здесь есть ловушка. Если пользователь вообще не заполнил поле, которое в форме помечено как необязательное, n8n может не создать этот ключ в JSON item вовсе. Тогда $json.email равен не пустой строке, а undefined — и условие === '' вернёт false. Невалидный item проскользнёт в ветку обработки, как будто всё нормально.
Надёжное условие закрывает оба случая сразу:
{{ !$json.email || $json.email.trim() === '' }}
!$json.email срабатывает, если ключ отсутствует или равен undefined/null/пустой строке. .trim() === '' добавляет защиту от строки, которая выглядит непустой, но состоит только из пробелов — например, если пользователь случайно нажал пробел и отправил форму.
В интерфейсе n8n условие IF настраивается в разделе Conditions: выбираем тип значения — Expression, и вставляем выражение выше. Можно добавить несколько условий и объединить их через AND/OR — например, проверять сразу имя и email.
Когда условие срабатывает (ветка true), item уходит дальше по этой ветке — туда будет подключён узел остановки. Ветка false при этом продолжает цепочку с чистыми и проверенными данными.
Остановка невалидного item: узел Stop and Error
Когда IF выявил проблему и отправил item в ветку true, нужно явно завершить выполнение — не просто «ничего не делать», а остановить цепочку с понятным сообщением. Для этого в n8n есть узел Stop and Error.
Его логика проста: как только item достигает этого узла, workflow прекращает выполнение и фиксирует ошибку с заданным текстом. Никакие последующие узлы не получат этот item.
В настройках Stop and Error одно ключевое поле — Error Message. Пишите туда что-то конкретное, а не «Ошибка»:
Email обязателен — заявка не принятаНе заполнено поле ИмяОписание не может быть пустым
Конкретное сообщение помогает при отладке: если workflow упадёт в продакшне, вы сразу поймёте, какое именно поле стало причиной.
Когда Stop and Error срабатывает во время тестирования, узел окрашивается в красный — это нормальное и ожидаемое поведение, не признак поломки workflow. В панели Output видно текст сообщения об ошибке. Именно так и должна выглядеть успешно работающая валидация: невалидный item остановлен, цепочка дальше не пошла.
Ловушка, которая проявляется раньше Stop and Error
Есть ситуация, при которой узел Edit Fields краснеет ещё до IF и до Stop and Error. Это происходит, если поле формы вообще отсутствует в JSON item — например, пользователь не заполнил необязательное поле, и n8n не создал для него ключ. Тогда expression вида:
{{ $json['Имя'].trim() }}
выбрасывает ошибку Cannot read properties of undefined (reading 'trim'). Потому что $json['Имя'] возвращает undefined, а у undefined нет метода .trim().
Решений два. Первое — пометить поле как Required прямо в настройках Form Trigger: тогда n8n не даст отправить форму без его заполнения. Второе — защитить expression тернарным оператором:
{{ $json['Имя'] ? $json['Имя'].trim() : '' }}
Здесь: если $json['Имя'] существует и непустое — применяем .trim(), иначе подставляем пустую строку. IF потом поймает эту пустую строку своим условием и отправит item в Stop and Error. Цепочка работает корректно.
Выбор между двумя подходами зависит от контекста: если поле действительно обязательное, лучше помечать его Required в форме — это останавливает проблему ещё до попадания в workflow. Тернарный оператор нужен для полей, которые могут прийти пустыми по задумке, но всё равно участвуют в нормализации.
Сборка полного workflow: нормализация → валидация → остановка
Теперь собираем всё в одну цепочку. Никаких новых узлов — только то, что уже разобрано, в правильном порядке.
Шаг 1. Form Trigger
Откройте workflow из предыдущего урока. Form Trigger уже настроен: поля «Имя», «Email», «Описание». Если Email помечен как Required, снимите пометку на время теста — нужно проверить, что валидация в IF работает даже когда форма пропускает пустое поле.
Шаг 2. Edit Fields — нормализация
Добавьте узел Edit Fields сразу после Form Trigger и подключите его. Создайте три поля, используя тернарный оператор из предыдущего раздела — он защищает от отсутствующего ключа:
name→ Expression:{{ $json['Имя'] ? $json['Имя'].trim() : '' }}email→ Expression:{{ $json['Email'] ? $json['Email'].trim().toLowerCase() : '' }}description→ Expression:{{ $json['Описание'] ? $json['Описание'].trim() : '' }}
После сохранения узла запустите тест формы с корректными данными и проверьте Output Edit Fields — там должны быть уже приведённые значения: без лишних пробелов, email строчными буквами.
Шаг 3. IF — проверка валидности
Добавьте узел IF и подключите его к Edit Fields. В разделе Conditions добавьте условие с типом Expression:
{{ !$json.email || $json.email.trim() === '' }}
Ветка true — невалидный item, ветка false — данные в порядке. Если нужно проверять несколько полей сразу, добавьте второе условие и объедините через OR:
{{ !$json.name || $json.name.trim() === '' }}
Шаг 4. Stop and Error — ветка true
Добавьте узел Stop and Error и подключите его к выходу true узла IF. В поле Error Message напишите конкретное сообщение:
Email обязателен — заявка не принята
Ветку false оставьте пока незаполненной — туда в следующем уроке подключится маршрутизация.
Шаг 5. Тестовый запуск с невалидными данными
Откройте форму по тестовой ссылке Form Trigger и отправьте заявку с пустым Email:
{ "Имя": " алексей ", "Email": "", "Описание": "Не работает вход" }
Что должно произойти:
Edit Fields обработает item, поле
emailстанет пустой строкой''.IF получит item: условие
!$json.email || $json.email.trim() === ''вернётtrue.Item уйдёт в ветку true → достигнет Stop and Error.
Узел Stop and Error окрасится в красный, в панели Output появится текст «Email обязателен — заявка не принята».
Это ожидаемый результат. Красный узел — не поломка, а подтверждение: валидация работает, некорректный item остановлен, дальше по цепочке ничего не пошло.
Для полноты картины отправьте форму ещё раз с заполненным Email. IF должен отправить item в ветку false — она пока ни к чему не подключена, и n8n просто не будет делать ничего дальше. Главное — Stop and Error при этом не срабатывает.
Цепочка готова. В уроке 6 к ветке false IF подключится логика маршрутизации — нормализованные и проверенные данные будут использоваться для разделения заявок на обычные и приоритетные.

Поток нормализации, валидации и остановки невалидной заявки.
Попробуйте решить
Ты хочешь привести поле «Имя», пришедшее из формы, к единообразному виду: убрать пробелы по краям и сделать все буквы строчными. Какая expression в узле Edit Fields решит эту задачу?
Продолжить с проверкой и прогрессом
Откройте интерактивный раннер с заданиями урока.
