N8n: декларативный язык выражений и его роль в автоматизации рабочих процессов
N8n — это платформа с открытым исходным кодом для автоматизации рабочих процессов (workflow automation), которая позволяет соединять различные приложения, базы данных и API без необходимости написания сложного кода. Центральным элементом, обеспечивающим гибкость и мощь платформы, является встроенный язык выражений, часто называемый «языком N8n» или «Expression Language». Этот язык не является языком программирования в традиционном смысле, а представляет собой декларативный язык шаблонов, предназначенный для извлечения, преобразования и динамического вычисления данных непосредственно внутри узлов рабочего процесса.
Архитектура и основные концепции языка выражений N8n
Язык выражений N8n построен вокруг концепции доступа к контексту выполнения рабочего процесса. Каждое выражение оценивается в конкретном контексте узла, что позволяет обращаться к данным, поступающим от других узлов, к переменным окружения, датам и встроенным функциям. Основной синтаксис заключается в использовании двойных фигурных скобок {{ }}, внутри которых и пишется выражение.
Ключевые контексты данных, доступные в выражениях:
- $json: Данные, полученные от предыдущего узла в формате JSON. Это основной контекст для работы.
- $binary: Данные в бинарном формате (например, изображения, файлы).
- $now: Текущая дата и время. Может быть модифицирована (например,
$now.plus(1, 'week')). - $execution: Информация о текущем выполнении рабочего процесса (ID, режим, метка времени).
- $vars: Пользовательские переменные, определенные в настройках рабочего процесса.
- $env: Переменные окружения, доступные в экземпляре n8n.
- $node: Позволяет получать данные от любого узла в workflow, даже если он еще не был выполнен в текущем запуске (с использованием метода
$node["Название узла"].json). {{ $json.fieldName }}— доступ к полю объекта.{{ $json["field-name-with-dashes"] }}— доступ к полю с дефисами.{{ $json.array[0].property }}— доступ к свойству первого элемента массива.{{ $now.format("YYYY-MM-DD") }}— форматирование текущей даты.{{ $if($json.value > 10; "Больше"; "Меньше или равно") }}— условное выражение.- Настройка параметров узла: Динамическое определение URL для HTTP-запроса, тела запроса, заголовков, условий в узле «IF».
- Преобразование данных в узле «Code»: Хотя узел «Code» позволяет писать JavaScript, выражения часто используются для подготовки входных данных для него.
- Формирование SQL-запросов: Динамическое построение запросов к базам данных на основе данных из предыдущих шагов.
- Создание пользовательских полей: Генерация сложных структур JSON, вычисляемых значений или человекочитаемых строк для уведомлений (например, в Telegram, Email).
- Маршрутизация и ветвление: Использование выражений в узле «Switch» для определения пути выполнения workflow на основе сложных условий.
- Узел «Shopify Trigger»: Получает данные о новом заказе. Выходные данные: JSON-объект
orderс полямиtotal_price,customer,id. - Узел «Set»: Создает вычисляемые поля.
- Поле 1:
discount-> Выражение:{{ $if($json.order.total_price > 100; 0.1; 0.05) }} - Поле 2:
final_price-> Выражение:{{ $json.order.total_price- (1 - $json.discount) }}
- Поле 1:
- Поле 3:
message-> Выражение:{{ $concat("Заказ
", $json.order.id, " от ", $json.order.customer.first_name, ". Сумма: $", $json.order.total_price, ". Скидка: ", $json.discount*100, "%. Итого: $", $round($json.final_price, 2)) }}
Синтаксис и методы работы с данными
Выражения в N8n могут быть как простыми ссылками на поля, так и сложными конструкциями с использованием функций и операторов. Доступ к свойствам объектов осуществляется через точечную нотацию или нотацию квадратных скобок для ключей со специальными символами.
Примеры базового синтаксиса:
Категории встроенных функций
Язык выражений N8n включает обширную библиотеку встроенных функций, разделенных на логические категории. Эти функции являются основным инструментом для манипуляции данными.
| Категория функций | Описание | Примеры функций |
|---|---|---|
| Строковые (String) | Операции над текстовыми данными: объединение, извлечение подстрок, поиск, замена, изменение регистра. | $concat(), $substring(), $replace(), $toUpperCase(), $trim() |
| Математические (Math) | Математические вычисления и агрегация числовых данных. | $sum(), $min(), $max(), $average(), $ceil(), $floor(), $round() |
| Дата и время (Date & Time) | Парсинг, форматирование, манипуляция и сравнение дат и времени. | $formatDate(), $now, $today, $fromNow(), $dateAdd() |
| Массивы (Array) | Создание, фильтрация, сортировка, агрегация и преобразование массивов. | $join(), $length(), $map(), $filter(), $sort(), $first(), $last() |
| Логические (Logical) | Условные операции и проверки, позволяющие реализовывать ветвление логики внутри выражения. | $if(), $and(), $or(), $not(), $compare(), $exists() |
| Работа с объектами (Object) | Создание и манипуляция объектами JSON. | $jsonObject(), $keys(), $values(), $merge() |
| Переменные окружения и контекста (Environment & Context) | Функции для доступа к мета-информации о выполнении и внешним переменным. | $env, $vars, $execution, $workflow |
Практическое применение языка выражений в узлах
Язык выражений используется практически в каждом поле узла n8n, где требуется динамическое значение. Вот ключевые области применения:
Пример рабочего процесса с использованием языка выражений
Рассмотрим сценарий: получение новых заказов из Shopify, расчет скидки на основе суммы заказа, форматирование сообщения и отправка в Slack.
{{ $json.message }}.Отладка и лучшие практики
N8n предоставляет встроенные инструменты для отладки выражений. При наведении курсора на поле, содержащее выражение, во всплывающей подсказке отображается вычисленное значение. В режиме выполнения workflow можно просмотреть детали каждого узла, включая входные и выходные данные, что критически важно для проверки корректности выражений.
Лучшие практики использования языка выражений:
- Избегайте излишней сложности: Если выражение становится слишком громоздким, рассмотрите возможность использования нескольких узлов «Set» или узла «Code» (JavaScript/Python).
- Используйте переменные ($vars): Для значений, повторяющихся в разных частях workflow (например, ID канала Slack, пороговые значения), задавайте переменные Workflow. Это упрощает поддержку.
- Проверяйте существование полей: Используйте функцию
$exists()для безопасного доступа к опциональным полям, чтобы избежать ошибок выполнения. - Документируйте сложную логику: Используйте узлы «Comment» для описания нетривиальных выражений.
- Экранируйте кавычки в строках: При использовании строк внутри выражений помните об экранировании:
{{ $concat('It's a sample') }}.
Сравнение с аналогичными системами
| Платформа | Подход к выражениям/скриптингу | Ключевые отличия от N8n |
|---|---|---|
| Zapier | Имеет встроенный конструктор «Formatter» с набором предопределенных операций, но менее гибкий язык шаблонов. | N8n Expression Language значительно мощнее и предлагает программную гибкость, близкую к коду, в то время как Zapier ориентирован на предзаданные преобразования. |
| Make (Integromat) | Использует мощные функции и выражения в полях модулей, схожие по концепции с N8n. | Подходы очень похожи. Make исторически имел более развитую систему функций, но N8n активно развивает свой язык и имеет преимущество в виде open-source модели. |
| Microsoft Power Automate | Использует функции в стиле Excel (например, concat()) и отдельный язык выражений для сложных сценариев в действиях. |
Синтаксис N8n более единообразен и интегрирован в поля. Power Automate часто требует использования отдельных действий «Compose» для вычислений. |
| Apache Airflow | Рабочие процессы определяются кодом на Python (DSL). Нет встроенного визуального языка выражений. | N8n предлагает более низкий порог входа за счет визуального конструктора и декларативного языка выражений, в то время как Airflow требует полноценного программирования. |
Ответы на часто задаваемые вопросы (FAQ)
Вопрос: Язык выражений N8n — это язык программирования?
Ответ: Нет, это не язык программирования общего назначения. Это предметно-ориентированный язык (DSL), предназначенный специально для доступа к данным контекста выполнения рабочего процесса, их преобразования с помощью встроенных функций. Он не поддерживает объявление пользовательских функций, циклов или сложных структур данных в отрыве от контекста узлов.
Вопрос: Можно ли расширить язык выражений, добавив свои собственные функции?
Ответ: Да, в self-hosted версии n8n это возможно путем создания пользовательских узлов. Вы можете разработать свой узел на JavaScript/TypeScript, который будет предоставлять новые функции, доступные затем в Expression Editor. Прямого механизма добавления одной лишь функции без создания узла не предусмотрено.
Вопрос: Что делать, если встроенных функций не хватает для сложной логики?
Ответ: В этом случае следует использовать узел «Code». Он позволяет написать скрипт на JavaScript или Python, реализующий любую необходимую логику. Результаты работы узла «Code» затем становятся доступны в последующих узлах через контекст $json, и с ними можно работать с помощью стандартного языка выражений.
Вопрос: Как обрабатывать ошибки, связанные с отсутствием ожидаемых данных в выражении?
Ответ: Рекомендуется использовать функцию $exists() для проверки наличия пути в данных. Например: {{ $if($exists($json.order.total_price); $json.order.total_price; 0) }}. Также полезно использовать отладчик n8n для проверки фактической структуры данных на выходе предыдущих узлов.
Вопрос: Есть ли ограничения на длину или сложность выражения?
Ответ: Жестких ограничений нет, но чрезмерно длинные и сложные выражения становятся трудными для чтения и отладки. Если выражение не помещается в поле ввода или содержит много вложенных функций, это сигнал к тому, чтобы разбить логику на несколько узлов «Set» или вынести ее в узел «Code».
Вопрос: Поддерживает ли язык выражений асинхронные операции или HTTP-запросы?
Ответ: Нет, язык выражений предназначен для синхронных вычислений на основе уже доступных данных в контексте workflow. Для выполнения HTTP-запросов, чтения файлов или других асинхронных операций необходимо использовать соответствующие узлы (HTTP Request, Read/Write File и т.д.).
Вопрос: Как в выражении получить данные из узла, который был выполнен в предыдущей итерации цикла или в другом потоке выполнения?
Ответ: Для этого используется метод $node. Например, {{ $node["Название узла"].json["property"] }} получит выходные данные указанного узла из его последнего успешного выполнения в рамках этого же workflow run. Это мощный механизм для кросс-узловых вычислений.
Комментарии