Guest User

n8n - system prompt

a guest
Jan 5th, 2025
3,540
2
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 55.21 KB | None | 2 0
  1. # Comprehensive Guide to Inline JavaScript and the Code Node in n8n
  2.  
  3. This comprehensive guide explores the utilization of **inline JavaScript transformations** and the **Code node** within n8n workflows. It is structured to provide a seamless understanding of both methods, their functionalities, built-in transformation functions, variables, and best practices. By the end of this guide, you'll be equipped to harness the full potential of JavaScript within your n8n automation workflows.
  4.  
  5. ---
  6.  
  7. ## Table of Contents
  8.  
  9. 1. [Introduction](#1-introduction)
  10. 2. [Inline Expressions vs. Code Node](#2-inline-expressions-vs-code-node)
  11. - [2.1 Key Differences](#21-key-differences)
  12. - [2.2 Tournament Templating Engine](#22-tournament-templating-engine)
  13. 3. [Inline Expressions and Built-in Transformations](#3-inline-expressions-and-built-in-transformations)
  14. - [3.1 Inline JavaScript Basics](#31-inline-javascript-basics)
  15. - [3.2 Data Transformation Functions](#32-data-transformation-functions)
  16. - [3.2.1 String Transformations](#321-string-transformations)
  17. - [3.2.2 Array Transformations](#322-array-transformations)
  18. - [3.2.3 Number Transformations](#323-number-transformations)
  19. - [3.2.4 Object Transformations](#324-object-transformations)
  20. - [3.2.5 Boolean Transformations](#325-boolean-transformations)
  21. - [3.2.6 Date & Time Transformations (Luxon)](#326-date--time-transformations-luxon)
  22. - [3.3 Combining Inline JS Methods](#333-combining-inline-js-methods)
  23. 4. [The Code Node](#4-the-code-node)
  24. - [4.1 Multiple Languages (JavaScript & Python)](#41-multiple-languages-javascript--python)
  25. - [4.2 Accessing the Current Node’s Input: `$input`](#42-accessing-the-current-nodes-input-input)
  26. - [4.3 Writing JavaScript in the Code Node](#43-writing-javascript-in-the-code-node)
  27. - [4.3.1 Accessing Input Data](#431-accessing-input-data)
  28. - [4.3.2 Modifying Data](#432-modifying-data)
  29. - [4.3.3 Returning Output Data](#433-returning-output-data)
  30. - [4.4 Using External npm Modules](#44-using-external-npm-modules)
  31. - [4.5 Debugging and Testing Your Code](#45-debugging-and-testing-your-code)
  32. - [4.6 Best Practices](#46-best-practices)
  33. - [4.6.1 Data Structure Awareness](#461-data-structure-awareness)
  34. - [4.6.2 Error Handling](#462-error-handling)
  35. - [4.6.3 Performance Considerations](#463-performance-considerations)
  36. - [4.7 Limitations of the Code Node](#47-limitations-of-the-code-node)
  37. 5. [Built-in Methods & Their Availability](#5-built-in-methods--their-availability)
  38. - [5.1 `$evaluateExpression`](#51-evaluateexpression)
  39. - [5.2 `$ifEmpty`](#52-ifempty)
  40. - [5.3 `$if`](#53-if)
  41. - [5.4 `$max` and `$min`](#54-max-and-min)
  42. 6. [Built-in Variables & Execution Metadata](#6-built-in-variables--execution-metadata)
  43. - [6.1 Workflow & Execution Details](#61-workflow--execution-details)
  44. - [6.2 HTTP Request Node–Specific Variables](#62-http-request-node-specific-variables)
  45. - [6.3 Global Variables: `$vars`](#63-global-variables-vars)
  46. 7. [Accessing Data from Other Nodes](#7-accessing-data-from-other-nodes)
  47. - [7.1 `$("NodeName").all(), .first(), .last(), etc.`](#71-nodenameall-first-last-etc)
  48. - [7.2 `$("NodeName").item`](#72-nodenameitem)
  49. - [7.3 `$("NodeName").itemMatching(index)`](#73-nodenameitemmatchingindex)
  50. 8. [Using JMESPath: `$jmespath`](#8-using-jmespath-jmespath)
  51. 9. [Data Transformation Functions (Inline Expressions)](#9-data-transformation-functions-inline-expressions)
  52. - [9.1 String Transformations](#91-string-transformations)
  53. - [9.2 Array Transformations](#92-array-transformations)
  54. - [9.3 Number Transformations](#93-number-transformations)
  55. - [9.4 Object Transformations](#94-object-transformations)
  56. - [9.5 Boolean Transformations](#95-boolean-transformations)
  57. - [9.6 Date & Time Transformations (Luxon)](#96-date--time-transformations-luxon)
  58. 10. [Putting It All Together: Examples](#10-putting-it-all-together-examples)
  59. - [10.1 Inline Example: LinkedIn URL Extraction](#101-inline-example-linkedin-url-extraction)
  60. - [10.2 Part 1 Example: Processing User Data](#102-part-1-example-processing-user-data)
  61. - [10.3 Part 2 Example: Generating Personalized Invoices](#103-part-2-example-generating-personalized-invoices)
  62. - [10.4 Code Node Example: Looping & Transforming Items](#104-code-node-example-looping--transforming-items)
  63. - [10.5 Code Node + JMESPath Example](#105-code-node--jmespath-example)
  64. 11. [Frequently Asked Questions (FAQ)](#11-frequently-asked-questions-faq)
  65. 12. [Practical Q&A and Tips](#12-practical-qa-and-tips)
  66. 13. [Further Reading and Resources](#13-further-reading-and-resources)
  67. 14. [Conclusion](#14-conclusion)
  68.  
  69. ---
  70.  
  71. ## 1. Introduction
  72.  
  73. **n8n** is a robust, open-source workflow automation tool that enables users to connect various applications and services, facilitating automated tasks without the need for extensive coding. Among its versatile nodes, the **Code node** and **inline JavaScript transformations** empower users to implement custom logic and data manipulations, enhancing the flexibility and power of workflows.
  74.  
  75. This guide is designed to provide a comprehensive understanding of these JavaScript integration methods, enabling you to harness their full potential within your n8n workflows. Whether you're performing simple data formatting or implementing complex business logic, mastering both inline expressions and the Code node will significantly enhance your automation capabilities.
  76.  
  77. ---
  78.  
  79. ## 2. Inline Expressions vs. Code Node
  80.  
  81. Understanding the distinction between **Inline Expressions** and the **Code Node** is crucial for effectively leveraging JavaScript within n8n workflows. Each method serves different purposes and is suited to different types of tasks.
  82.  
  83. ### 2.1 Key Differences
  84.  
  85. | Aspect | Inline Expressions | Code Node |
  86. |-------------------------------|--------------------------------------------------------|--------------------------------------------|
  87. | **Where** | Directly in node parameters (toggle “Fixed / Expression”) | As a separate node in the workflow |
  88. | **Syntax** | Single‐line JavaScript wrapped in `{{ }}` | Full multi‐line JavaScript (or Python) |
  89. | **Ideal Use Case** | Quick transformations (like `.isEmail()`, `.sum()`) | More complex logic (loops, conditionals, multiple variables) |
  90. | **Access to n8n Helpers** | Some helpers are inline‐only (`$if()`, `$itemIndex`) | Many helpers are available, but not all (e.g., `$if()` is not) |
  91. | **Data Handling** | Must remain on a single line | No line limits; can perform multi‐step code |
  92.  
  93. ### 2.2 Tournament Templating Engine
  94.  
  95. Starting in n8n **v1.9.0**, expressions use an enhanced engine nicknamed “**Tournament**,” which provides built‐in **data transformation functions** out of the box. These functions allow you to perform operations like `.isEmail()`, `.extractDomain()`, `.removeDuplicates()`, and more directly on your data types (strings, arrays, numbers, etc.) within inline expressions.
  96.  
  97. ---
  98.  
  99. ## 3. Inline Expressions and Built-in Transformations
  100.  
  101. Inline Expressions in n8n allow you to embed JavaScript directly within node parameters, enabling dynamic data manipulation without the need for separate nodes. This section delves into the basics of inline expressions, their syntax, and the powerful transformation functions available.
  102.  
  103. ### 3.1 Inline JavaScript Basics
  104.  
  105. Whenever you have a node parameter that can switch between *Fixed* and *Expression* modes, you can insert code in the form:
  106.  
  107. ```text
  108. {{ <your JavaScript here> }}
  109. ```
  110.  
  111. - **Single-line**: All logic must fit on one line.
  112. - **JavaScript Features**: You can use standard JS string or array methods (e.g., `.split()`, `.join()`, `.map()`) alongside n8n’s built-in “data transformation functions” if the data type matches (string, array, etc.).
  113. - **Chaining**: You can chain multiple functions (both built-in and vanilla JS) on a single value.
  114.  
  115. **Example:**
  116.  
  117. ```text
  118. {{ "[email protected]".isEmail() }}
  119. // => true
  120. ```
  121.  
  122. Here, `.isEmail()` is a built-in transformation function available for **strings**.
  123.  
  124. ### 3.2 Data Transformation Functions
  125.  
  126. n8n's **Tournament Templating Engine** introduces a suite of **data transformation functions** categorized by data type. These functions can be chained and combined with standard JavaScript methods to perform complex transformations within inline expressions.
  127.  
  128. #### 3.2.1 String Transformations
  129.  
  130. - **`.isEmail()`**: Checks if the string is a valid email.
  131. - **`.extractDomain()`**: Extracts the domain from a URL.
  132. - **`.removeTags()`**: Removes HTML tags from text.
  133. - **`.base64Encode()` / `.base64Decode()`**: Encodes or decodes the string in Base64.
  134. - **`.toSnakeCase()`** / `.toCamelCase()`**: Converts the string to snake_case or camelCase.
  135. - **`.extractUrlPath()`**: Extracts the path from a URL.
  136.  
  137. **Examples:**
  138.  
  139. ```text
  140. {{ "[email protected]".isEmail() }}
  141. // Returns: true
  142.  
  143. {{ "https://www.example.com/path".extractDomain() }}
  144. // Returns: "www.example.com"
  145.  
  146. {{ "<p>Sample Text</p>".removeTags() }}
  147. // Returns: "Sample Text"
  148.  
  149. {{ "Hello World!".toSnakeCase() }}
  150. // Returns: "hello_world!"
  151. ```
  152.  
  153. #### 3.2.2 Array Transformations
  154.  
  155. - **`.sum()`**: Sums all numerical elements in the array.
  156. - **`.removeDuplicates()`**: Eliminates duplicate elements.
  157. - **`.merge(array)`**: Merges another array into the current one.
  158. - **`.isEmpty()`**: Checks if the array has no elements.
  159. - **`.randomItem()`**: Retrieves a random element from the array.
  160. - **`.first()`** / **`.last()`**: Retrieves the first or last element.
  161.  
  162. **Examples:**
  163.  
  164. ```text
  165. {{ [1, 2, 2, 4].removeDuplicates() }}
  166. // Returns: [1, 2, 4]
  167.  
  168. {{ [10, 20, 30].sum() }}
  169. // Returns: 60
  170.  
  171. {{ [1, 2, 3].merge([4, 5]) }}
  172. // Returns: [1, 2, 3, 4, 5]
  173. ```
  174.  
  175. #### 3.2.3 Number Transformations
  176.  
  177. - **`.round(decimalPlaces)`**: Rounds the number to the specified decimal places.
  178. - **`.toBoolean()`**: Converts the number to a boolean (`0` → `false`, any other number → `true`).
  179. - **`.format(locale)`**: Formats the number according to the specified locale.
  180. - **`.isEven()`** / **`.isOdd()`**: Checks if the number is even or odd.
  181.  
  182. **Examples:**
  183.  
  184. ```text
  185. {{ 123.456.round(2) }}
  186. // Returns: 123.46
  187.  
  188. {{ 0.toBoolean() }}
  189. // Returns: false
  190.  
  191. {{ 10.isEven() }}
  192. // Returns: true
  193. ```
  194.  
  195. #### 3.2.4 Object Transformations
  196.  
  197. - **`.isEmpty()`**: Checks if the object has no keys.
  198. - **`.removeField(key)`**: Removes a specified key from the object.
  199. - **`.merge(object)`**: Merges another object into the current one.
  200. - **`.toJsonString()`**: Converts the object to a JSON string.
  201.  
  202. **Examples:**
  203.  
  204. ```text
  205. {{ { "name": "Alice", "age": 30 }.isEmpty() }}
  206. // Returns: false
  207.  
  208. {{ { "name": "Alice" }.removeField("age") }}
  209. // Returns: { "name": "Alice" }
  210.  
  211. {{ { "name": "Alice" }.merge({ "age": 30, "city": "New York" }) }}
  212. // Returns: { "name": "Alice", "age": 30, "city": "New York" }
  213. ```
  214.  
  215. #### 3.2.5 Boolean Transformations
  216.  
  217. - **`.toInt()`**: Converts `true` to `1` and `false` to `0`.
  218.  
  219. **Examples:**
  220.  
  221. ```text
  222. {{ true.toInt() }}
  223. // Returns: 1
  224.  
  225. {{ false.toInt() }}
  226. // Returns: 0
  227. ```
  228.  
  229. #### 3.2.6 Date & Time Transformations (Luxon)
  230.  
  231. n8n integrates the [Luxon](https://moment.github.io/luxon/) library for comprehensive date operations within inline expressions.
  232.  
  233. - **`.toDateTime()`**: Parses a string into a Luxon `DateTime` object.
  234. - **`.plus(amount, unit)`**: Adds a specified amount of time.
  235. - **`.minus(amount, unit)`**: Subtracts a specified amount of time.
  236. - **`.format(formatString)`**: Formats the date according to the given pattern.
  237. - **`.isWeekend()`**: Checks if the date falls on a weekend.
  238.  
  239. **Examples:**
  240.  
  241. ```text
  242. {{ "2025-01-03".toDateTime().plus(3, "days").format("yyyy-MM-dd") }}
  243. // Returns: "2025-01-06"
  244.  
  245. {{ "2025-01-03".toDateTime().isWeekend() }}
  246. // Returns: false (assuming January 3, 2025, is a Friday)
  247.  
  248. {{ "2025-01-03".toDateTime().minus(1, "week").format("MMMM dd, yyyy") }}
  249. // Returns: "December 27, 2024"
  250. ```
  251.  
  252. ### 3.3 Combining Inline JS Methods
  253.  
  254. You can mix **built-in transformations** with standard JavaScript methods to perform more intricate data manipulations.
  255.  
  256. **Examples:**
  257.  
  258. ```text
  259. {{ "https://example.com/path".extractDomain().toUpperCase() }}
  260. // Returns: "EXAMPLE.COM"
  261.  
  262. {{ $("NodeName").item.json.someArray
  263. .removeDuplicates()
  264. .join(", ")
  265. .toUpperCase() }}
  266. // Returns a string of unique array elements joined by commas and in uppercase
  267. ```
  268.  
  269. This flexibility allows for powerful one-liner transformations that can handle complex data processing tasks directly within node parameters.
  270.  
  271. ---
  272.  
  273. ## 4. The Code Node
  274.  
  275. When your workflow requires more elaborate logic—such as multiple lines of code, loops, conditionals, or the use of external libraries—the **Code node** is the ideal choice. This section explores the functionalities and best practices associated with the Code node.
  276.  
  277. ### 4.1 Multiple Languages (JavaScript & Python)
  278.  
  279. The Code node supports writing scripts in **JavaScript** and optionally **Python**. While JavaScript is the primary language, Python support allows for leveraging Python's extensive libraries and functionalities within your workflows.
  280.  
  281. - **JavaScript**: Offers full multi-line scripting capabilities, access to n8n's built-in helpers, and the ability to write complex logic.
  282. - **Python**: Provides an alternative for those more comfortable with Python, though it lacks direct access to n8n's JavaScript-specific transformations.
  283.  
  284. **Note**: Switching to Python means you won't have access to JavaScript-specific built-in transformation functions like `.isEmail()` or `.sum()`.
  285.  
  286. ### 4.2 Accessing the Current Node’s Input: `$input`
  287.  
  288. Inside the Code node, `$input` is the primary way to access the data flowing into the node. Depending on the execution mode, you can retrieve all input items or process each item individually.
  289.  
  290. | Property / Method | Purpose | In Code Node? |
  291. |------------------------------|-------------------------------------------------------------------------|---------------|
  292. | `$input.item` | Current item (in “Run Once for Each Item” mode). | ✓ |
  293. | `$input.all()` | Array of all input items. | ✓ |
  294. | `$input.first()` | The first item. | ✓ |
  295. | `$input.last()` | The last item. | ✓ |
  296. | `$input.params` | Node configuration parameters from previous steps. | ✓ |
  297. | `$json` | Shorthand for `$input.item.json` (if running once per item). | ✓ (context) |
  298. | `$input.context.noItemsLeft` | Use in loops to detect if no more items exist. | ✓ |
  299.  
  300. **Example** (in a Code node running once per item):
  301.  
  302. ```javascript
  303. const current = $input.item;
  304. const data = current.json;
  305. data.newField = "Hello!";
  306. return [{ json: data }];
  307. ```
  308.  
  309. ### 4.3 Writing JavaScript in the Code Node
  310.  
  311. Once the Code node is added and configured, you can begin writing your JavaScript code. This involves accessing input data, modifying it as needed, and returning the processed data.
  312.  
  313. #### 4.3.1 Accessing Input Data
  314.  
  315. Depending on the execution mode, you can access all input items or the current item being processed.
  316.  
  317. - **Run Once for All Items**:
  318.  
  319. ```javascript
  320. const items = $input.all();
  321. ```
  322.  
  323. - **Explanation**: Fetches all incoming items into an array called `items`. Each item typically contains a `json` property with the data.
  324.  
  325. - **Run Once for Each Item**:
  326.  
  327. ```javascript
  328. const item = $input.item;
  329. ```
  330.  
  331. - **Explanation**: Retrieves the current item being processed. Useful when the node is set to execute once per item.
  332.  
  333. **Example**:
  334.  
  335. ```javascript
  336. // Code Node (JavaScript)
  337.  
  338. // For "Run Once for All Items" mode
  339. const items = $input.all();
  340.  
  341. // For "Run Once for Each Item" mode
  342. const item = $input.item;
  343. ```
  344.  
  345. #### 4.3.2 Modifying Data
  346.  
  347. You can manipulate the data as needed, whether processing all items collectively or handling each item individually.
  348.  
  349. - **Processing All Items Together**:
  350.  
  351. ```javascript
  352. const processedItems = items.map(item => {
  353. // Example: Add a new field
  354. item.json.newField = 'New Value';
  355. return item;
  356. });
  357. ```
  358.  
  359. - **Processing Each Item Individually**:
  360.  
  361. ```javascript
  362. // Example: Modify a specific field
  363. item.json.existingField = item.json.existingField.toUpperCase();
  364. return item;
  365. ```
  366.  
  367. **Example**:
  368.  
  369. ```javascript
  370. // Code Node (JavaScript)
  371.  
  372. // Run Once for All Items
  373. const processedItems = items.map(item => {
  374. // Add a timestamp to each item
  375. item.json.processedAt = new Date().toISOString();
  376. return item;
  377. });
  378.  
  379. return processedItems;
  380.  
  381. // Run Once for Each Item
  382. item.json.processedAt = new Date().toISOString();
  383. return item;
  384. ```
  385.  
  386. #### 4.3.3 Returning Output Data
  387.  
  388. After processing, ensure your code returns the modified data in the expected format.
  389.  
  390. - **For "Run Once for All Items"**:
  391.  
  392. ```javascript
  393. return processedItems;
  394. ```
  395.  
  396. - **For "Run Once for Each Item"**:
  397.  
  398. ```javascript
  399. return item;
  400. ```
  401.  
  402. **Example**:
  403.  
  404. ```javascript
  405. // Code Node (JavaScript)
  406.  
  407. // Run Once for All Items
  408. return processedItems;
  409.  
  410. // Run Once for Each Item
  411. return item;
  412. ```
  413.  
  414. ### 4.4 Using External npm Modules
  415.  
  416. Leveraging external npm modules can significantly enhance the capabilities of your Code node. However, this feature is **only available if you are self-hosting n8n**.
  417.  
  418. #### Enabling External Modules
  419.  
  420. 1. **Self-Hosted Requirement**:
  421. - Ensure you are running a self-hosted instance of n8n. Cloud-hosted versions might not support this feature due to security restrictions.
  422.  
  423. 2. **Install Modules**:
  424. - Navigate to your n8n installation directory.
  425. - Use `npm` or `yarn` to install the desired module. For example:
  426.  
  427. ```bash
  428. npm install lodash
  429. ```
  430.  
  431. #### Importing and Using Modules
  432.  
  433. Once the module is installed, you can import and use it within the Code node.
  434.  
  435. ```javascript
  436. const _ = require('lodash');
  437.  
  438. const items = $input.all();
  439.  
  440. const processedItems = items.map(item => {
  441. // Example: Use lodash to clone the item
  442. const clonedItem = _.cloneDeep(item.json);
  443. clonedItem.newField = 'Cloned Value';
  444. return { json: clonedItem };
  445. });
  446.  
  447. return processedItems;
  448. ```
  449.  
  450. **Example: Using Axios for HTTP Requests**
  451.  
  452. ```javascript
  453. const axios = require('axios');
  454.  
  455. const items = $input.all();
  456.  
  457. const processedItems = await Promise.all(items.map(async item => {
  458. const response = await axios.get(`https://api.example.com/data/${item.json.id}`);
  459. item.json.externalData = response.data;
  460. return item;
  461. }));
  462.  
  463. return processedItems;
  464. ```
  465.  
  466. *This script fetches additional data from an external API for each item.*
  467.  
  468. **Note**: Always ensure that the modules you use are compatible with the Node.js version running n8n.
  469.  
  470. ### 4.5 Debugging and Testing Your Code
  471.  
  472. Ensuring your code works as intended is crucial. n8n provides tools to aid in debugging:
  473.  
  474. #### Logging
  475.  
  476. - **Use `console.log()`**:
  477. - Outputs messages and data to the n8n logs, which can be viewed in the workflow execution details.
  478.  
  479. ```javascript
  480. console.log('Input Items:', items);
  481. ```
  482.  
  483. - **Example**:
  484.  
  485. ```javascript
  486. // Code Node (JavaScript)
  487. console.log('Processing the following items:', items);
  488.  
  489. const processedItems = items.map(item => {
  490. item.json.processed = true;
  491. return item;
  492. });
  493.  
  494. return processedItems;
  495. ```
  496.  
  497. #### Testing with Sample Data
  498.  
  499. - **Execute Workflow Manually**:
  500. - Run the workflow with test data to observe how the Code node processes it.
  501. - Check the output data to verify correctness.
  502.  
  503. - **Handle Errors Gracefully**:
  504. - Implement error handling to catch and log issues without breaking the entire workflow.
  505.  
  506. ```javascript
  507. try {
  508. // Your code logic
  509. } catch (error) {
  510. console.error('An error occurred:', error);
  511. // Optionally, you can throw the error to stop the workflow
  512. throw error;
  513. }
  514. ```
  515.  
  516. **Example**:
  517.  
  518. ```javascript
  519. // Code Node (JavaScript)
  520.  
  521. try {
  522. const items = $input.all();
  523. const processedItems = items.map(item => {
  524. if (!item.json.email) {
  525. throw new Error('Email is missing for item ID: ' + item.json.id);
  526. }
  527. item.json.email = item.json.email.toLowerCase();
  528. return item;
  529. });
  530. return processedItems;
  531. } catch (error) {
  532. console.error('Processing error:', error);
  533. throw error; // This will stop the workflow and mark it as failed
  534. }
  535. ```
  536.  
  537. ### 4.6 Best Practices
  538.  
  539. Adhering to best practices ensures your Code node scripts are efficient, maintainable, and error-resistant.
  540.  
  541. #### 4.6.1 Data Structure Awareness
  542.  
  543. - **Understand Input Data**:
  544. - Familiarize yourself with the structure of incoming data (`item.json`) to manipulate it effectively.
  545.  
  546. - **Consistent Output Structure**:
  547. - Ensure the output data maintains a consistent structure to prevent issues in downstream nodes.
  548.  
  549. **Example**:
  550.  
  551. ```javascript
  552. // Ensure 'user' field exists before modifying
  553. if (item.json.user && typeof item.json.user === 'object') {
  554. item.json.user.isActive = true;
  555. } else {
  556. item.json.user = { isActive: true };
  557. }
  558. return item;
  559. ```
  560.  
  561. #### 4.6.2 Error Handling
  562.  
  563. - **Implement Try-Catch Blocks**:
  564. - Capture and handle potential errors to prevent workflow failures.
  565.  
  566. ```javascript
  567. try {
  568. // Code that might throw an error
  569. } catch (error) {
  570. console.error('Error processing item:', error);
  571. // Decide whether to throw the error or handle it
  572. throw error;
  573. }
  574. ```
  575.  
  576. - **Validate Data**:
  577. - Check for the existence of necessary fields before processing to avoid undefined errors.
  578.  
  579. ```javascript
  580. if (!item.json.requiredField) {
  581. throw new Error('requiredField is missing');
  582. }
  583. ```
  584.  
  585. **Example**:
  586.  
  587. ```javascript
  588. // Code Node (JavaScript)
  589. try {
  590. const items = $input.all();
  591. const processedItems = items.map(item => {
  592. if (!item.json.email) {
  593. throw new Error('Email is missing for user: ' + item.json.name);
  594. }
  595. item.json.email = item.json.email.toLowerCase();
  596. return item;
  597. });
  598. return processedItems;
  599. } catch (error) {
  600. console.error('Processing error:', error);
  601. throw error;
  602. }
  603. ```
  604.  
  605. #### 4.6.3 Performance Considerations
  606.  
  607. - **Optimize Loops**:
  608. - Use efficient looping methods like `.map()` or `.forEach()` instead of traditional `for` loops where possible.
  609.  
  610. - **Limit External Calls**:
  611. - Minimize API calls or database queries within the Code node to enhance performance, especially in "Run Once for All Items" mode.
  612.  
  613. - **Avoid Blocking Operations**:
  614. - Ensure that your code doesn't include long-running synchronous operations that can delay workflow execution.
  615.  
  616. **Example**:
  617.  
  618. ```javascript
  619. // Code Node (JavaScript)
  620.  
  621. // Efficiently map over items without unnecessary operations
  622. const processedItems = items.map(item => {
  623. item.json.processed = true;
  624. return item;
  625. });
  626.  
  627. return processedItems;
  628. ```
  629.  
  630. ### 4.7 Limitations of the Code Node
  631.  
  632. While the Code Node is a powerful tool, it's essential to be aware of its limitations to set appropriate expectations and design workflows accordingly.
  633.  
  634. 1. **Execution Environment**:
  635. - The Code Node runs in a sandboxed environment with certain restrictions for security reasons. Some Node.js APIs or modules might not be available.
  636.  
  637. 2. **Resource Constraints**:
  638. - Intensive computations or processing large datasets can impact performance. Always test and optimize your code for efficiency.
  639.  
  640. 3. **External Modules (Self-Hosted Only)**:
  641. - The ability to use external npm modules is limited to self-hosted n8n instances. Cloud-hosted versions typically do not support this feature.
  642.  
  643. 4. **Error Propagation**:
  644. - Unhandled errors within the Code Node can cause the entire workflow to fail. Implement robust error handling to mitigate this.
  645.  
  646. 5. **State Persistence**:
  647. - The Code Node does not maintain state between executions. Each run is stateless unless you explicitly store and retrieve state using external storage solutions.
  648.  
  649. 6. **Security Concerns**:
  650. - Executing custom code can introduce security vulnerabilities. Ensure that your code is secure, especially when handling sensitive data or integrating with external systems.
  651.  
  652. **Example of a Limitation**:
  653.  
  654. ```javascript
  655. // Attempting to use a restricted Node.js module
  656. const fs = require('fs'); // This will throw an error as 'fs' is not allowed
  657. ```
  658.  
  659. *This script will fail because the `fs` module is restricted in n8n's sandboxed environment.*
  660.  
  661. ---
  662.  
  663. ## 5. Built-in Methods & Their Availability
  664.  
  665. n8n provides a suite of **built-in helper methods** that simplify data manipulation within both inline expressions and the Code node. Understanding their availability and proper usage is key to effective workflow automation.
  666.  
  667. ### 5.1 `$evaluateExpression(expression: string, itemIndex?: number)`
  668.  
  669. **Availability**: **Yes** in Code node
  670.  
  671. - **Purpose**: Interprets a string as an **inline** n8n expression from within a Code node.
  672. - **Usage**:
  673.  
  674. ```javascript
  675. // Evaluate with default item index = 0
  676. const result = $evaluateExpression('{{$json.property}}');
  677.  
  678. // Evaluate with item index = 2
  679. const result2 = $evaluateExpression('{{$json.property}}', 2);
  680. ```
  681.  
  682. **Example**:
  683.  
  684. ```javascript
  685. // Code Node (JavaScript)
  686.  
  687. // Evaluate an inline expression for the current item
  688. let greeting = $evaluateExpression('{{ "Hello, " + $json.firstName + "!" }}', i);
  689. ```
  690.  
  691. ### 5.2 `$ifEmpty(value, defaultValue)`
  692.  
  693. **Availability**: **Yes** in Code node
  694.  
  695. - **Purpose**: Returns `defaultValue` if `value` is `null`, `undefined`, empty string, empty array, or empty object; otherwise returns `value`.
  696. - **Usage**:
  697.  
  698. ```javascript
  699. const fallbackName = $ifEmpty($json.username, 'GuestUser');
  700. ```
  701.  
  702. **Example**:
  703.  
  704. ```javascript
  705. // Code Node (JavaScript)
  706. const username = $ifEmpty(item.json.username, 'Guest');
  707. item.json.displayName = username;
  708. ```
  709.  
  710. ### 5.3 `$if(condition, valueIfTrue, valueIfFalse)`
  711.  
  712. **Availability**: **No** in Code node
  713.  
  714. - **Purpose**: Inline‐only helper for quick ternary logic.
  715. - **Inline Expression Usage**:
  716.  
  717. ```text
  718. {{ $if($json.age > 18, "Adult", "Minor") }}
  719. ```
  720.  
  721. - **Code Node Alternative**:
  722.  
  723. ```javascript
  724. const status = condition ? valueIfTrue : valueIfFalse;
  725. ```
  726.  
  727. **Example**:
  728.  
  729. ```javascript
  730. // Code Node (JavaScript)
  731. const status = (item.json.score >= 70) ? "Pass" : "Fail";
  732. item.json.status = status;
  733. ```
  734.  
  735. ### 5.4 `$max` and `$min`
  736.  
  737. **Availability**: **No** in Code node
  738.  
  739. - **Purpose**: Inline‐only helpers to determine the maximum or minimum value among provided numbers.
  740. - **Inline Expression Usage**:
  741.  
  742. ```text
  743. {{ $max(10, 20, 30) }}
  744. {{ $min(10, 20, 30) }}
  745. ```
  746.  
  747. - **Code Node Alternative**:
  748.  
  749. ```javascript
  750. const maxValue = Math.max(10, 20, 30);
  751. const minValue = Math.min(10, 20, 30);
  752. ```
  753.  
  754. **Example**:
  755.  
  756. ```javascript
  757. // Code Node (JavaScript)
  758. const highestScore = Math.max(item.json.score1, item.json.score2, item.json.score3);
  759. item.json.highestScore = highestScore;
  760. ```
  761.  
  762. ---
  763.  
  764. ## 6. Built-in Variables & Execution Metadata
  765.  
  766. n8n provides a range of **global variables** and **execution metadata** that can be accessed within both inline expressions and the Code node. These variables offer valuable context about the workflow's execution, environment, and state.
  767.  
  768. ### 6.1 Workflow & Execution Details
  769.  
  770. | Variable | Description | In Code Node? |
  771. |---------------------------------|--------------------------------------------------------------------------|---------------|
  772. | `$workflow.id` | Unique identifier of the workflow. | ✓ |
  773. | `$workflow.name` | Name of the workflow. | ✓ |
  774. | `$workflow.active` | Indicates if the workflow is active (`true`) or inactive (`false`). | ✓ |
  775. | `$execution.id` | Unique ID of the current workflow run. | ✓ |
  776. | `$execution.mode` | Execution mode: `test` or `production`. | ✓ |
  777. | `$execution.resumeUrl` | URL to resume a workflow waiting at a Wait node. | ✓ |
  778. | `$execution.customData` | Custom data you can store for this execution. | ✓ |
  779. | `$env` | Accesses environment variables of the n8n instance. | ✓ |
  780. | `$secrets` | Accesses your [External secrets](https://docs.n8n.io/credentials/external-secrets/) configuration. | ✓ |
  781. | `$getWorkflowStaticData(type)` | Retrieves persisted data (`global` or `node`). | ✓ |
  782.  
  783. **Inline-Expression-Only Variables**:
  784.  
  785. - `$itemIndex`: Index of the current item in inline expressions. **Not** valid in the Code node.
  786. - `$version`: Alias for node version in inline expressions. **Not** valid in the Code node.
  787.  
  788. ### 6.2 HTTP Request Node–Specific Variables
  789.  
  790. Only accessible **inside the HTTP Request node’s inline expressions**:
  791.  
  792. | Variable | Description |
  793. |---------------|----------------------------------------------------------------|
  794. | `$pageCount` | Number of pages fetched so far (with built-in pagination). |
  795. | `$request` | The outgoing request object (headers, method, etc.). |
  796. | `$response` | The response object (body, headers, statusCode). |
  797.  
  798. **Note**: These variables **do not** exist in the Code node or other nodes.
  799.  
  800. ### 6.3 Global Variables: `$vars`
  801.  
  802. You can define **global variables** in the n8n **Variables** panel (left sidebar). Once created, they are accessible anywhere (including the Code node):
  803.  
  804. ```javascript
  805. const val = $vars.myVariable;
  806. // All $vars are read‐only strings
  807. ```
  808.  
  809. - **Read-only** at runtime.
  810. - If you need to store data persistently, consider using `$getWorkflowStaticData('global')` or `$getWorkflowStaticData('node')`.
  811.  
  812. **Example**:
  813.  
  814. ```javascript
  815. // Code Node (JavaScript)
  816. const defaultShipping = $vars.defaultShipping || 'Standard';
  817. item.json.shippingMethod = $ifEmpty(item.json.shippingMethod, defaultShipping);
  818. ```
  819.  
  820. ---
  821.  
  822. ## 7. Accessing Data from Other Nodes
  823.  
  824. n8n expressions and Code nodes allow referencing data from **other nodes** using the `$("<node-name>")` syntax. This capability is essential for creating dynamic and interconnected workflows.
  825.  
  826. ### 7.1 `$("NodeName").all(), .first(), .last(), etc.`
  827.  
  828. These methods allow you to retrieve data from a specified node.
  829.  
  830. - **`.all(bIdx?, rIdx?)`**: Retrieves **all items** from the node’s output.
  831. - **`.first(bIdx?, rIdx?)`**: Retrieves the **first item** from the node.
  832. - **`.last(bIdx?, rIdx?)`**: Retrieves the **last item** from the node.
  833.  
  834. **Examples**:
  835.  
  836. - **Inline Expression**:
  837.  
  838. ```text
  839. {{ $("HTTP Request1").item.json.someField }}
  840. ```
  841.  
  842. - **Code Node**:
  843.  
  844. ```javascript
  845. const httpItems = $("HTTP Request1").all(); // Array of items
  846. const firstItem = $("HTTP Request1").first();
  847. ```
  848.  
  849. ### 7.2 `$("NodeName").item`
  850.  
  851. - **Availability**: **Inline expressions only**.
  852. - **Purpose**: Retrieves the item aligned with the current `$itemIndex`.
  853.  
  854. **Example**:
  855.  
  856. ```text
  857. {{ $("UserFetcher").item.json.email }}
  858. ```
  859.  
  860. ### 7.3 `$("NodeName").itemMatching(index)`
  861.  
  862. - **Availability**: **Code node–only**.
  863. - **Purpose**: Retrieves the item from the specified node that matches the current input item's index. Useful for correlated data retrieval in loop scenarios.
  864.  
  865. **Example**:
  866.  
  867. ```javascript
  868. // Code Node (JavaScript)
  869. // Retrieving the matching order for the current user
  870. const matchingOrder = $("OrderFetcher").itemMatching($input.context.currentNodeInputIndex);
  871. item.json.orderDetails = matchingOrder.json;
  872. ```
  873.  
  874. ---
  875.  
  876. ## 8. Using JMESPath: `$jmespath`
  877.  
  878. **JMESPath** is a powerful query language for JSON. In n8n, you can use the `$jmespath` function within the Code node to filter or transform data based on JMESPath queries.
  879.  
  880. **Example**:
  881.  
  882. ```javascript
  883. // Code node example
  884. const data = {
  885. users: [
  886. { name: 'Alice', age: 30 },
  887. { name: 'Bob', age: 25 }
  888. ]
  889. };
  890.  
  891. const result = $jmespath(data, 'users[?age > `25`].name');
  892. // => ["Alice"]
  893.  
  894. return [{ json: { result } }];
  895. ```
  896.  
  897. This script filters users older than 25 and extracts their names.
  898.  
  899. ---
  900.  
  901. ## 9. Data Transformation Functions (Inline Expressions)
  902.  
  903. The “Tournament” engine in n8n provides **chainable** transformation functions for various data types—strings, arrays, numbers, objects, booleans, and dates—within inline expressions. These functions simplify complex data manipulations into concise, readable expressions.
  904.  
  905. ### 9.1 String Transformations
  906.  
  907. - **`.isEmail()`**: Check if the string is a valid email.
  908. - **`.extractDomain()`**: Extract the domain from a URL.
  909. - **`.removeTags()`**: Remove HTML tags from text.
  910. - **`.base64Encode()` / `.base64Decode()`**: Encode or decode the string in Base64.
  911. - **`.toSnakeCase()` / `.toCamelCase()`**: Convert the string to snake_case or camelCase.
  912. - **`.extractUrlPath()`**: Extract the path from a URL.
  913.  
  914. **Example**:
  915.  
  916. ```text
  917. {{ "[email protected]".isEmail() }}
  918. // => true
  919.  
  920. {{ "https://www.example.com/path".extractDomain() }}
  921. // => "www.example.com"
  922.  
  923. {{ "<p>Sample Text</p>".removeTags() }}
  924. // => "Sample Text"
  925.  
  926. {{ "Hello World!".toSnakeCase() }}
  927. // => "hello_world!"
  928. ```
  929.  
  930. ### 9.2 Array Transformations
  931.  
  932. - **`.sum()`**: Sum all numbers in the array.
  933. - **`.removeDuplicates()`**: Eliminate duplicate elements.
  934. - **`.merge(arr2, arr3, ...)`**: Merge multiple arrays.
  935. - **`.isEmpty()`**: Check if the array has no elements.
  936. - **`.randomItem()`**: Retrieve a random element from the array.
  937. - **`.first()`** / **`.last()`**: Retrieve the first or last element.
  938.  
  939. **Example**:
  940.  
  941. ```text
  942. {{ [1, 2, 2, 4].removeDuplicates() }}
  943. // => [1, 2, 4]
  944.  
  945. {{ [10, 20, 30].sum() }}
  946. // => 60
  947.  
  948. {{ [1, 2, 3].merge([4, 5]) }}
  949. // => [1, 2, 3, 4, 5]
  950. ```
  951.  
  952. ### 9.3 Number Transformations
  953.  
  954. - **`.round(decimals)`**: Round to the specified number of decimal places.
  955. - **`.toBoolean()`**: Convert the number to a boolean (`0` → `false`, nonzero → `true`).
  956. - **`.format(locale)`**: Format the number according to the specified locale.
  957. - **`.isEven()`** / **`.isOdd()`**: Check if the number is even or odd.
  958.  
  959. **Example**:
  960.  
  961. ```text
  962. {{ 123.456.round(2) }}
  963. // => 123.46
  964.  
  965. {{ 0.toBoolean() }}
  966. // => false
  967.  
  968. {{ 10.isEven() }}
  969. // => true
  970. ```
  971.  
  972. ### 9.4 Object Transformations
  973.  
  974. - **`.isEmpty()`**: Check if the object has no keys.
  975. - **`.removeField(key)`**: Remove a specified key from the object.
  976. - **`.merge(object2)`**: Merge another object into the current one.
  977. - **`.toJsonString()`**: Convert the object to a JSON string.
  978.  
  979. **Example**:
  980.  
  981. ```text
  982. {{ { "email": "[email protected]", "name": "John" }.removeField("name") }}
  983. // => { "email": "[email protected]" }
  984.  
  985. {{ { "name": "Alice" }.merge({ "age": 30, "city": "New York" }) }}
  986. // => { "name": "Alice", "age": 30, "city": "New York" }
  987. ```
  988.  
  989. ### 9.5 Boolean Transformations
  990.  
  991. - **`.toInt()`**: Convert `true` to `1` and `false` to `0`.
  992.  
  993. **Example**:
  994.  
  995. ```text
  996. {{ true.toInt() }}
  997. // => 1
  998.  
  999. {{ false.toInt() }}
  1000. // => 0
  1001. ```
  1002.  
  1003. ### 9.6 Date & Time Transformations (Luxon)
  1004.  
  1005. Leveraging the Luxon library, n8n allows comprehensive date and time manipulations within inline expressions.
  1006.  
  1007. - **`.toDateTime()`**: Parse a string into a Luxon `DateTime` object.
  1008. - **`.plus(amount, unit)`**: Add a specified amount of time.
  1009. - **`.minus(amount, unit)`**: Subtract a specified amount of time.
  1010. - **`.format(formatString)`**: Format the date according to the given pattern.
  1011. - **`.isWeekend()`**: Check if the date falls on a weekend.
  1012.  
  1013. **Example**:
  1014.  
  1015. ```text
  1016. {{ "2025-01-03".toDateTime().plus(3, "days").format("yyyy-MM-dd") }}
  1017. // => "2025-01-06"
  1018.  
  1019. {{ "2025-01-03".toDateTime().isWeekend() }}
  1020. // => false (assuming January 3, 2025, is a Friday)
  1021.  
  1022. {{ "2025-01-03".toDateTime().minus(1, "week").format("MMMM dd, yyyy") }}
  1023. // => "December 27, 2024"
  1024. ```
  1025.  
  1026. ---
  1027.  
  1028. ## 10. Putting It All Together: Examples
  1029.  
  1030. To solidify your understanding, let's walk through several practical examples that demonstrate how to apply inline expressions and the Code node in real-world scenarios.
  1031.  
  1032. ### 10.1 Inline Example: LinkedIn URL Extraction
  1033.  
  1034. **Scenario**: Extract the numeric ID from a LinkedIn activity URL.
  1035.  
  1036. **Input Data**:
  1037.  
  1038. ```json
  1039. {
  1040. "query": {
  1041. "url": "https://www.linkedin.com/feed/update/urn:li:activity:7281671012738314240/"
  1042. }
  1043. }
  1044. ```
  1045.  
  1046. **Inline Expression**:
  1047.  
  1048. ```text
  1049. {{ $("LinkedIn").item.json.query.url.extractUrlPath()
  1050. .split(":")[3]
  1051. .replace('/', '') }}
  1052. ```
  1053.  
  1054. **Explanation**:
  1055.  
  1056. 1. `.extractUrlPath()` → returns `"/feed/update/urn:li:activity:7281671012738314240/"`
  1057. 2. `.split(":")` → splits the string by `":"`, resulting in `["/feed/update/urn", "li", "activity", "7281671012738314240/"]`
  1058. 3. `[3]` → selects the fourth element: `"7281671012738314240/"`
  1059. 4. `.replace('/', '')` → removes the trailing slash, yielding `"7281671012738314240"`
  1060.  
  1061. **Result**:
  1062.  
  1063. ```
  1064. 7281671012738314240
  1065. ```
  1066.  
  1067. ### 10.2 Part 1 Example: Processing User Data
  1068.  
  1069. To illustrate the concepts of **inline JavaScript transformations**, let's walk through a practical example where we process user data to ensure data integrity and enhance profiles.
  1070.  
  1071. #### Scenario
  1072.  
  1073. You receive a list of user profiles from a previous node. Each user profile may have missing or improperly formatted data. Your tasks are:
  1074.  
  1075. 1. **Ensure Every User Has an Email**:
  1076. - If the email is missing, set it to `[email protected]`.
  1077.  
  1078. 2. **Assign a Default Role**:
  1079. - If the user's roles array is empty, assign a default role of `"guest"`.
  1080.  
  1081. 3. **Format User Names**:
  1082. - Combine `firstName` and `lastName` into a `fullName` property in snake_case.
  1083.  
  1084. #### Input Data
  1085.  
  1086. ```json
  1087. [
  1088. { "firstName": "John", "lastName": "Doe", "email": "[email protected]", "roles": ["user"] },
  1089. { "firstName": "Jane", "lastName": "Smith", "roles": [] },
  1090. { "firstName": "Emily", "lastName": "Jones", "email": "[email protected]" }
  1091. ]
  1092. ```
  1093.  
  1094. #### Objectives
  1095.  
  1096. - **Set Default Email**:
  1097. - Use `$ifEmpty` to ensure every user has an email address.
  1098.  
  1099. - **Assign Default Role**:
  1100. - Use `$ifEmpty` to assign a default role if the roles array is empty.
  1101.  
  1102. - **Create Full Name in Snake Case**:
  1103. - Combine `firstName` and `lastName`, then convert to snake_case using `.toSnakeCase()`.
  1104.  
  1105. #### Inline Expressions Implementation
  1106.  
  1107. **1. Set Default Email**:
  1108.  
  1109. ```text
  1110. {{ $ifEmpty($json.email, '[email protected]') }}
  1111. ```
  1112.  
  1113. **2. Assign Default Role**:
  1114.  
  1115. ```text
  1116. {{ $ifEmpty($json.roles, ['guest']) }}
  1117. ```
  1118.  
  1119. **3. Create Full Name in Snake Case**:
  1120.  
  1121. ```text
  1122. {{ ($json.firstName + " " + $json.lastName).toSnakeCase() }}
  1123. ```
  1124.  
  1125. #### Applying Inline Expressions in Node Parameters
  1126.  
  1127. Assume you're using a **Set** node to define new fields based on the transformations.
  1128.  
  1129. - **Set Email**:
  1130. - **Field Name:** `email`
  1131. - **Value:**
  1132. ```text
  1133. {{ $ifEmpty($json.email, '[email protected]') }}
  1134. ```
  1135.  
  1136. - **Set Roles**:
  1137. - **Field Name:** `roles`
  1138. - **Value:**
  1139. ```text
  1140. {{ $ifEmpty($json.roles, ['guest']) }}
  1141. ```
  1142.  
  1143. - **Set Full Name**:
  1144. - **Field Name:** `fullName`
  1145. - **Value:**
  1146. ```text
  1147. {{ ($json.firstName + " " + $json.lastName).toSnakeCase() }}
  1148. ```
  1149.  
  1150. #### Resulting Output
  1151.  
  1152. ```json
  1153. [
  1154. {
  1155. "firstName": "John",
  1156. "lastName": "Doe",
  1157. "email": "[email protected]",
  1158. "roles": ["user"],
  1159. "fullName": "john_doe"
  1160. },
  1161. {
  1162. "firstName": "Jane",
  1163. "lastName": "Smith",
  1164. "email": "[email protected]",
  1165. "roles": ["guest"],
  1166. "fullName": "jane_smith"
  1167. },
  1168. {
  1169. "firstName": "Emily",
  1170. "lastName": "Jones",
  1171. "email": "[email protected]",
  1172. "roles": ["guest"],
  1173. "fullName": "emily_jones"
  1174. }
  1175. ]
  1176. ```
  1177.  
  1178. **Explanation**:
  1179.  
  1180. - **User 1 (John Doe)**:
  1181. - Email exists and remains unchanged.
  1182. - Roles are already assigned as `["user"]`.
  1183. - `fullName` is formatted as `"john_doe"`.
  1184.  
  1185. - **User 2 (Jane Smith)**:
  1186. - Email is missing; set to `"[email protected]"`.
  1187. - Roles array is empty; assigned default role `["guest"]`.
  1188. - `fullName` is formatted as `"jane_smith"`.
  1189.  
  1190. - **User 3 (Emily Jones)**:
  1191. - Email exists and remains unchanged.
  1192. - Roles are missing; assigned default role `["guest"]`.
  1193. - `fullName` is formatted as `"emily_jones"`.
  1194.  
  1195. ### 10.3 Part 2 Example: Generating Personalized Invoices
  1196.  
  1197. In this example, we'll utilize the **Code Node** to generate personalized invoices for users based on their order data. This process involves complex data manipulation, conditional logic, and the integration of multiple transformation methods.
  1198.  
  1199. #### Scenario
  1200.  
  1201. You receive a list of user orders from a previous node. Each order contains user information and a list of purchased items. Your tasks are:
  1202.  
  1203. 1. **Generate a Personalized Greeting**:
  1204. - Create a greeting message for each user based on their first and last names.
  1205.  
  1206. 2. **Calculate Total Order Amount**:
  1207. - Sum the total cost of all items in the order.
  1208.  
  1209. 3. **Assign a Shipping Method**:
  1210. - If the shipping method is missing, assign a default shipping method of `"Standard"`.
  1211.  
  1212. 4. **Extract Product Names**:
  1213. - Use JMESPath to extract a list of product names from the order items.
  1214.  
  1215. 5. **Add Timestamps and Workflow Metadata**:
  1216. - Add a timestamp indicating when the invoice was processed.
  1217. - Include the workflow ID for reference.
  1218.  
  1219. 6. **Handle Missing Data Gracefully**:
  1220. - Use `$ifEmpty` to manage missing fields and ensure data integrity.
  1221.  
  1222. #### Input Data
  1223.  
  1224. ```json
  1225. [
  1226. {
  1227. "customer": { "firstName": "Alice", "lastName": "Wonderland", "email": "[email protected]" },
  1228. "items": [
  1229. { "product": "Book", "quantity": 2, "price": 15.99 },
  1230. { "product": "Pen", "quantity": 5, "price": 1.99 }
  1231. ],
  1232. "shippingMethod": "Express"
  1233. },
  1234. {
  1235. "customer": { "firstName": "Bob", "lastName": "Builder", "email": "" },
  1236. "items": [
  1237. { "product": "Hammer", "quantity": 1, "price": 25.50 }
  1238. ]
  1239. // Missing shippingMethod
  1240. }
  1241. ]
  1242. ```
  1243.  
  1244. #### Objectives
  1245.  
  1246. 1. **Generate Personalized Greeting**:
  1247. - Use `$evaluateExpression` to create a greeting like `"Dear Alice Wonderland,"`.
  1248.  
  1249. 2. **Calculate Total Order Amount**:
  1250. - Sum the products of `quantity` and `price` for all items.
  1251.  
  1252. 3. **Assign Default Shipping Method**:
  1253. - Use `$ifEmpty` to set shipping method to `"Standard"` if it's missing.
  1254.  
  1255. 4. **Extract Product Names**:
  1256. - Use JMESPath to retrieve an array of product names.
  1257.  
  1258. 5. **Add Timestamps and Workflow Metadata**:
  1259. - Add `processedAt` timestamp.
  1260. - Include `workflowId`.
  1261.  
  1262. 6. **Handle Missing Data Gracefully**:
  1263. - Ensure that if the email is missing or empty, it’s handled appropriately.
  1264.  
  1265. #### Code Node Implementation
  1266.  
  1267. ```javascript
  1268. // Code Node (JavaScript)
  1269.  
  1270. // Retrieve all incoming items
  1271. const items = $input.all();
  1272.  
  1273. // Retrieve workflow ID from metadata
  1274. const workflowId = $workflow.id;
  1275.  
  1276. // Retrieve custom data or set default
  1277. const customData = $execution.customData.invoiceData || 'No custom data set';
  1278.  
  1279. // Retrieve global variable for default shipping
  1280. const defaultShipping = $vars.defaultShipping || 'Standard';
  1281.  
  1282. // Initialize array to hold processed items
  1283. let newItems = [];
  1284.  
  1285. // Iterate over each item
  1286. for (let i = 0; i < items.length; i++) {
  1287. let item = items[i].json;
  1288.  
  1289. try {
  1290. // 1. Generate Personalized Greeting
  1291. let greeting = $evaluateExpression('{{"Dear " + $json.customer.firstName + " " + $json.customer.lastName + ","}}', i);
  1292.  
  1293. // 2. Calculate Total Order Amount
  1294. let totalAmount = item.items.reduce((acc, currentItem) => acc + (currentItem.quantity * currentItem.price), 0);
  1295. totalAmount = totalAmount.toFixed(2); // Format to two decimal places
  1296.  
  1297. // 3. Assign Default Shipping Method if missing
  1298. let shippingMethod = $ifEmpty(item.shippingMethod, defaultShipping);
  1299.  
  1300. // 4. Extract Product Names using JMESPath
  1301. let productNames = $jmespath(item, 'items[].product');
  1302.  
  1303. // 5. Add Timestamps and Workflow Metadata
  1304. let processedAt = new Date().toISOString();
  1305.  
  1306. // 6. Handle Missing Email
  1307. let email = $ifEmpty(item.customer.email, '[email protected]');
  1308.  
  1309. // Update the item with new fields
  1310. item.greeting = greeting;
  1311. item.totalAmount = totalAmount;
  1312. item.shippingMethod = shippingMethod;
  1313. item.productNames = productNames;
  1314. item.processedAt = processedAt;
  1315. item.workflowId = workflowId;
  1316. item.email = email;
  1317. item.customData = customData;
  1318.  
  1319. // Add the updated item to the newItems array
  1320. newItems.push({
  1321. json: item,
  1322. });
  1323. } catch (error) {
  1324. console.error('Error processing item:', error);
  1325. // Optionally, add error details to the item
  1326. item.error = error.message;
  1327. newItems.push({
  1328. json: item,
  1329. });
  1330. }
  1331. }
  1332.  
  1333. // Return the array of processed items
  1334. return newItems;
  1335. ```
  1336.  
  1337. #### Explanation
  1338.  
  1339. 1. **Retrieve Input Data and Metadata**:
  1340. - `const items = $input.all();` fetches all incoming items.
  1341. - `const workflowId = $workflow.id;` gets the current workflow's ID.
  1342. - `const customData = $execution.customData.invoiceData || 'No custom data set';` retrieves custom execution data or sets a default.
  1343.  
  1344. 2. **Global Variable for Default Shipping**:
  1345. - `const defaultShipping = $vars.defaultShipping || 'Standard';` accesses a global variable or defaults to `"Standard"`.
  1346.  
  1347. 3. **Processing Each Item**:
  1348. - **Personalized Greeting**:
  1349. - Utilizes `$evaluateExpression` to dynamically create a greeting message.
  1350. - **Total Order Amount**:
  1351. - Uses `.reduce()` to calculate the sum of all items (`quantity * price`).
  1352. - Formats the total to two decimal places using `.toFixed(2)`.
  1353. - **Default Shipping Method**:
  1354. - Applies `$ifEmpty` to assign `"Standard"` if `shippingMethod` is missing.
  1355. - **Extract Product Names**:
  1356. - Employs JMESPath to extract an array of product names.
  1357. - **Timestamps and Metadata**:
  1358. - Adds a `processedAt` timestamp.
  1359. - Includes `workflowId` for reference.
  1360. - **Handle Missing Email**:
  1361. - Uses `$ifEmpty` to set a default email if the user's email is missing or empty.
  1362.  
  1363. 4. **Error Handling**:
  1364. - Implements a `try-catch` block to handle and log errors without stopping the entire workflow.
  1365. - Adds an `error` field to the item if an exception occurs.
  1366.  
  1367. 5. **Returning Processed Items**:
  1368. - The modified items are returned for use in subsequent nodes.
  1369.  
  1370. #### Resulting Output
  1371.  
  1372. ```json
  1373. [
  1374. {
  1375. "customer": { "firstName": "Alice", "lastName": "Wonderland", "email": "[email protected]" },
  1376. "items": [
  1377. { "product": "Book", "quantity": 2, "price": 15.99 },
  1378. { "product": "Pen", "quantity": 5, "price": 1.99 }
  1379. ],
  1380. "shippingMethod": "Express",
  1381. "greeting": "Dear Alice Wonderland,",
  1382. "totalAmount": "37.93",
  1383. "productNames": ["Book", "Pen"],
  1384. "processedAt": "2025-01-05T12:34:56.789Z",
  1385. "workflowId": "wf_123456789",
  1386. "email": "[email protected]",
  1387. "customData": "No custom data set"
  1388. },
  1389. {
  1390. "customer": { "firstName": "Bob", "lastName": "Builder", "email": "" },
  1391. "items": [
  1392. { "product": "Hammer", "quantity": 1, "price": 25.50 }
  1393. ],
  1394. "shippingMethod": "Standard",
  1395. "greeting": "Dear Bob Builder,",
  1396. "totalAmount": "25.50",
  1397. "productNames": ["Hammer"],
  1398. "processedAt": "2025-01-05T12:34:56.789Z",
  1399. "workflowId": "wf_123456789",
  1400. "email": "[email protected]",
  1401. "customData": "No custom data set"
  1402. }
  1403. ]
  1404. ```
  1405.  
  1406. **Explanation**:
  1407.  
  1408. - **User 1 (Alice Wonderland)**:
  1409. - **Greeting**: `"Dear Alice Wonderland,"`
  1410. - **Total Amount**: `$37.93` calculated from `(2 * 15.99) + (5 * 1.99)`
  1411. - **Shipping Method**: `"Express"`
  1412. - **Product Names**: `["Book", "Pen"]`
  1413. - **Processed At**: Timestamp when the invoice was generated.
  1414. - **Workflow ID**: Identifier of the workflow execution.
  1415. - **Email**: `"[email protected]"` remains unchanged.
  1416.  
  1417. - **User 2 (Bob Builder)**:
  1418. - **Greeting**: `"Dear Bob Builder,"`
  1419. - **Total Amount**: `$25.50` calculated from `(1 * 25.50)`
  1420. - **Shipping Method**: `"Standard"` assigned by default as it was missing.
  1421. - **Product Names**: `["Hammer"]`
  1422. - **Processed At**: Timestamp when the invoice was generated.
  1423. - **Workflow ID**: Identifier of the workflow execution.
  1424. - **Email**: `"[email protected]"` assigned by default due to missing or empty email.
  1425.  
  1426. ### 10.4 Code Node Example: Looping & Transforming Items
  1427.  
  1428. Below is a **JavaScript** Code node script that:
  1429.  
  1430. - Loops over all input items.
  1431. - Uses `$evaluateExpression` to dynamically process inline expressions.
  1432. - Uses `$ifEmpty` to provide fallback values.
  1433. - Reads global variables via `$vars`.
  1434. - Attaches new fields to each item.
  1435.  
  1436. ```javascript
  1437. // Code node (JavaScript)
  1438.  
  1439. const items = $input.all(); // all incoming items
  1440. const workflowId = $workflow.id; // workflow metadata
  1441. const customData = $execution.customData.myCustomKey || 'None set';
  1442.  
  1443. let newItems = [];
  1444.  
  1445. for (let i = 0; i < items.length; i++) {
  1446. let itemData = items[i].json;
  1447.  
  1448. // Evaluate an inline expression on item i
  1449. let computedValue = $evaluateExpression('{{ "Hello " + $json.name }}', i);
  1450.  
  1451. // Fallback if itemData.name is empty
  1452. let safeName = $ifEmpty(itemData.name, 'Unknown');
  1453.  
  1454. // Attach new fields
  1455. itemData.computedValue = computedValue;
  1456. itemData.workflowId = workflowId;
  1457. itemData.globalVar = $vars.myGlobalVal; // from Variables panel
  1458. itemData.customData = customData;
  1459. itemData.finalName = safeName;
  1460.  
  1461. newItems.push({ json: itemData });
  1462. }
  1463.  
  1464. return newItems;
  1465. ```
  1466.  
  1467. ### 10.5 Code Node + JMESPath Example
  1468.  
  1469. ```javascript
  1470. // Code node (JavaScript)
  1471. const data = {
  1472. products: [
  1473. { name: "Laptop", price: 1000, category: "electronics" },
  1474. { name: "Banana", price: 1, category: "food" },
  1475. { name: "Headphones", price: 200, category: "electronics" }
  1476. ]
  1477. };
  1478.  
  1479. // Filter only electronics, then get their prices
  1480. const electronicsPrices = $jmespath(data, 'products[?category == `electronics`].price');
  1481. // => [1000, 200]
  1482.  
  1483. return [{ json: { electronicsPrices } }];
  1484. ```
  1485.  
  1486. **Explanation**:
  1487.  
  1488. This script filters products in the "electronics" category and extracts their prices, resulting in an array `[1000, 200]`.
  1489.  
  1490. ---
  1491.  
  1492. ## 11. Frequently Asked Questions (FAQ)
  1493.  
  1494. 1. **Can I write multi-line JavaScript in inline expressions?**
  1495. - **No.** Inline expressions must be single-line. For multi-line logic, use a **Code Node** or **Function Node**.
  1496.  
  1497. 2. **Do built-in transformation functions replace standard JavaScript methods?**
  1498. - **No.** They are complementary. You can still use standard JavaScript methods like `.split()`, `.map()`, `.replace()` alongside built-in transformation functions.
  1499.  
  1500. 3. **Why isn’t my inline expression working?**
  1501. - **Possible Reasons:**
  1502. - Ensure the parameter is in **Expression mode** (toggle from *Fixed* to *Expression*).
  1503. - Verify the expression is enclosed within `{{ ... }}`.
  1504. - Check for syntax errors such as unclosed parentheses or multi-line code.
  1505. - Confirm the data type is appropriate for the methods being called.
  1506.  
  1507. 4. **Does n8n support languages other than JavaScript for inline expressions?**
  1508. - **No.** Inline expressions are JavaScript-only. However, the **Code Node** also supports Python for more extensive scripting needs.
  1509.  
  1510. 5. **How do I handle undefined variables in expressions?**
  1511. - Use functions like `$ifEmpty()` to provide default values when variables might be undefined or null.
  1512.  
  1513. 6. **Can I modify global variables at runtime?**
  1514. - **No.** `$vars` are read-only at runtime. To persist changes, use `$getWorkflowStaticData()` within the Code Node.
  1515.  
  1516. 7. **How can I debug my Code Node scripts?**
  1517. - Utilize `console.log()` statements within your Code Node to output intermediate values. These logs can be viewed in the n8n execution logs for troubleshooting.
  1518.  
  1519. 8. **Can I use external libraries in the Code Node?**
  1520. - **JavaScript Code Node:** Limited to built-in Node.js modules. For additional libraries, you may need to use HTTP requests or other integration methods.
  1521. - **Python Code Node:** Allows importing and using standard Python libraries.
  1522.  
  1523. ---
  1524.  
  1525. ## 12. Practical Q&A and Tips
  1526.  
  1527. 1. **Can I write multi-line JS in node parameters?**
  1528. - **No.** Inline expressions must remain one line. Use a Code node for multi-line.
  1529.  
  1530. 2. **Do the built-in transformations replace normal JavaScript methods?**
  1531. - **Not at all.** They are just convenient shortcuts. You can still do `.split()`, `.map()`, `.join()`, or any native JS.
  1532.  
  1533. 3. **What if `$if(...)` or `$max(...)` is not available in the Code node?**
  1534. - Use standard JavaScript equivalents: the ternary operator for `$if()`, `Math.max()` for `$max()`, etc.
  1535.  
  1536. 4. **Why is my inline expression not working?**
  1537. - Make sure you toggled to **Expression** mode.
  1538. - Wrap the code in `{{ ... }}`.
  1539. - Avoid multi-line or unbalanced parentheses.
  1540.  
  1541. 5. **Does n8n support other languages for expressions?**
  1542. - **Inline expressions** are JS‐only. The Code node can do JavaScript or Python, but the built‐in transformations (`.isEmail()`, etc.) are available only for JavaScript.
  1543.  
  1544. 6. **What about `$vars`? Can I change them mid‐execution?**
  1545. - `$vars` are read‐only at runtime. For persistent changes, use `$getWorkflowStaticData('global')` or `'node'`.
  1546.  
  1547. 7. **What are `$now` and `$today`?**
  1548. - `$now` → A Luxon `DateTime` for the current time.
  1549. - `$today` → A Luxon `DateTime` set to midnight of the current day.
  1550. - Both can be used in the Code node (JavaScript) or inline expressions for date calculations.
  1551.  
  1552. **Additional Tips**:
  1553.  
  1554. - **Use Descriptive Variable Names**: Enhance readability by using clear and descriptive names for variables and functions.
  1555. - **Modularize Your Code**: Break down complex scripts into smaller, reusable functions within the Code node.
  1556. - **Leverage Comments**: Document your code with comments to explain complex logic or transformations.
  1557. - **Test Incrementally**: Build and test your scripts incrementally to identify and fix issues early.
  1558. - **Secure Your Workflows**: Avoid exposing sensitive data within your scripts. Use n8n's secret management features where necessary.
  1559.  
  1560. ---
  1561.  
  1562. ## 13. Further Reading and Resources
  1563.  
  1564. - **n8n Documentation:** [Expressions](https://docs.n8n.io/)
  1565. - **JMESPath Documentation:** [jmespath.org](https://jmespath.org/)
  1566. - **Luxon Library Documentation:** [moment.github.io/luxon](https://moment.github.io/luxon/)
  1567. - **n8n GitHub Repository:** [github.com/n8n-io/n8n](https://github.com/n8n-io/n8n)
  1568. - **n8n Community Forum:** [community.n8n.io](https://community.n8n.io/)
  1569. - **JMESPath Tutorial:** [JMESPath Tutorial](https://jmespath.org/tutorial.html)
  1570. - **Luxon Tutorial:** [Luxon Tutorial](https://moment.github.io/luxon/docs/manual/tutorial.html)
  1571. - **JavaScript MDN Guide:** [MDN JavaScript Guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide)
  1572. - **npm Documentation:** [npm Docs](https://docs.npmjs.com/)
Add Comment
Please, Sign In to add comment