Code Node
Khi built-in nodes không đủ, Code node cho bạn viết JavaScript tùy ý — từ data processing đến API calls phức tạp.
🎯 Mục tiêu bài học
🎯 Mục tiêu
- Viết code trong n8n Code node
- Xử lý data phức tạp
- Call external APIs
- Build reusable logic
Checkpoint
Khi nào cần dùng Code node thay vì built-in nodes? Cho ví dụ cụ thể.
📖 Code Node Basics
1. Code Node Basics
1.1 Two Modes
| Mode | Description | Use Case |
|---|---|---|
| Run Once for All Items | Code chạy 1 lần, nhận tất cả items | Aggregation, sorting, complex logic |
| Run Once for Each Item | Code chạy cho từng item riêng | Transform, validate each item |
1.2 Hello World
1// Mode: Run Once for Each Item2// Input: Each item from previous node34const name = $input.item.json.name;5const greeting = 'Hello, ' + name + '!';67return {8 json: {9 greeting,10 processedAt: new Date().toISOString()11 }12};1.3 Access Input Data
1// === Run Once for Each Item ===2const item = $input.item.json;3// item.name, item.email, item.price...45// === Run Once for All Items ===6const items = $input.all();7// items[0].json.name, items[1].json.name...89// Access by node name10const webhookData = $('Webhook').item.json;11const sheetsData = $('Google Sheets').all();1.4 Return Data
1// Return single item2return {3 json: { result: "success", value: 42 }4};56// Return multiple items7return [8 { json: { name: "A", score: 95 } },9 { json: { name: "B", score: 87 } },10 { json: { name: "C", score: 72 } }11];1213// Return nothing (filter out item)14return [];Checkpoint
Phân biệt "Run Once for All Items" và "Run Once for Each Item". Khi nào dùng mode nào?
📊 Data Processing
2. Data Processing
2.1 Map & Transform
1// Mode: Run Once for All Items2const items = $input.all();34const transformed = items.map(item => {5 const d = item.json;6 return {7 json: {8 fullName: (d.firstName + ' ' + d.lastName).trim(),9 email: d.email.toLowerCase().trim(),10 revenue: d.quantity * d.unitPrice,11 category: categorize(d.revenue),12 isVIP: d.totalSpend > 1000000013 }14 };15});1617function categorize(amount) {18 if (amount > 5000000) return 'Premium';19 if (amount > 1000000) return 'Standard';20 return 'Basic';21}2223return transformed;2.2 Filter Complex Conditions
1// Mode: Run Once for All Items2const items = $input.all();34const filtered = items.filter(item => {5 const d = item.json;6 const createdDate = new Date(d.createdAt);7 const thirtyDaysAgo = new Date();8 thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);9 10 return (11 d.status === 'active' &&12 d.amount > 0 &&13 d.email.includes('@') &&14 createdDate > thirtyDaysAgo15 );16});1718return filtered;2.3 Group By & Aggregate
1// Mode: Run Once for All Items2const items = $input.all();34// Group by category5const groups = {};6for (const item of items) {7 const cat = item.json.category;8 if (!groups[cat]) {9 groups[cat] = { count: 0, totalRevenue: 0, items: [] };10 }11 groups[cat].count++;12 groups[cat].totalRevenue += item.json.revenue;13 groups[cat].items.push(item.json.name);14}1516// Convert to array of items17return Object.entries(groups).map(([category, data]) => ({18 json: {19 category,20 count: data.count,21 totalRevenue: data.totalRevenue,22 avgRevenue: Math.round(data.totalRevenue / data.count),23 topItems: data.items.slice(0, 5)24 }25}));2.4 Deduplicate with Priority
1// Keep highest-value duplicate2const items = $input.all();3const unique = new Map();45for (const item of items) {6 const key = item.json.email;7 const existing = unique.get(key);8 9 if (!existing || item.json.value > existing.json.value) {10 unique.set(key, item);11 }12}1314return Array.from(unique.values());Checkpoint
Viết code Group By category và tính tổng revenue. Dùng approach nào?
📝 String & Date Processing
3. String & Date Processing
3.1 Vietnamese Text Processing
1// Remove Vietnamese diacritics2function removeDiacritics(str) {3 return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');4}56// Slug generation7function toSlug(text) {8 return removeDiacritics(text)9 .toLowerCase()10 .replace(/[^a-z0-9]+/g, '-')11 .replace(/^-|-$/g, '');12}1314const name = $input.item.json.name; // "Nguyễn Văn Anh"15return {16 json: {17 name,18 slug: toSlug(name), // "nguyen-van-anh"19 search: removeDiacritics(name) // "Nguyen Van Anh"20 }21};3.2 Date Operations
1// Parse & format dates2const dateStr = $input.item.json.date; // "2026-01-20"3const date = new Date(dateStr);45const day = date.getDate().toString().padStart(2, '0');6const month = (date.getMonth() + 1).toString().padStart(2, '0');7const year = date.getFullYear();89return {10 json: {11 original: dateStr,12 formatted: day + '/' + month + '/' + year, // "20/01/2026"13 dayOfWeek: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'][date.getDay()],14 isWeekend: [0, 6].includes(date.getDay()),15 daysFromNow: Math.ceil((date - new Date()) / (1000 * 60 * 60 * 24))16 }17};3.3 Parse Unstructured Text
1// Extract info from email body2const body = $input.item.json.emailBody;34// Extract order number: "Order #12345"5const orderMatch = body.match(/Order #(\d+)/i);6const orderId = orderMatch ? orderMatch[1] : null;78// Extract amount: "Total: 1,500,000 VND"9const amountMatch = body.match(/Total:\s*([\d,]+)\s*VND/i);10const amount = amountMatch 11 ? parseInt(amountMatch[1].replace(/,/g, ''))12 : null;1314// Extract email15const emailMatch = body.match(/[\w.-]+@[\w.-]+\.\w+/);16const email = emailMatch ? emailMatch[0] : null;1718return {19 json: { orderId, amount, email, rawBody: body }20};Checkpoint
Hàm removeDiacritics hoạt động như thế nào? Regex /[\u0300-\u036f]/g match cái gì?
🌐 HTTP Requests in Code
4. HTTP Requests in Code
4.1 Fetch API
1// Mode: Run Once for Each Item2const userId = $input.item.json.userId;34const response = await fetch('https://api.example.com/users/' + userId, {5 method: 'GET',6 headers: {7 'Authorization': 'Bearer ' + $env.API_TOKEN,8 'Content-Type': 'application/json'9 }10});1112if (!response.ok) {13 throw new Error('API error: ' + response.status);14}1516const userData = await response.json();1718return {19 json: {20 ...($input.item.json),21 userName: userData.name,22 userEmail: userData.email23 }24};4.2 POST Request
1const payload = {2 model: "gpt-4o-mini",3 messages: [4 { role: "system", content: "Classify this text as positive/negative/neutral." },5 { role: "user", content: $input.item.json.text }6 ],7 temperature: 08};910const response = await fetch('https://api.openai.com/v1/chat/completions', {11 method: 'POST',12 headers: {13 'Authorization': 'Bearer ' + $env.OPENAI_API_KEY,14 'Content-Type': 'application/json'15 },16 body: JSON.stringify(payload)17});1819const data = await response.json();20const sentiment = data.choices[0].message.content;2122return {23 json: {24 text: $input.item.json.text,25 sentiment26 }27};Checkpoint
Cách gọi API bằng fetch() trong Code node? Cần await và xử lý response ra sao?
🛡️ Error Handling
5. Error Handling
5.1 Try-Catch
1try {2 const data = JSON.parse($input.item.json.rawData);3 const result = processData(data);4 5 return {6 json: { success: true, result }7 };8} catch (error) {9 return {10 json: {11 success: false,12 error: error.message,13 originalData: $input.item.json.rawData14 }15 };16}5.2 Validation
1function validate(item) {2 const errors = [];3 4 if (!item.email || !item.email.includes('@'))5 errors.push('Invalid email');6 7 if (!item.name || item.name.length < 2)8 errors.push('Name too short');9 10 if (item.amount && item.amount < 0)11 errors.push('Negative amount');12 13 return errors;14}1516const errors = validate($input.item.json);1718if (errors.length > 0) {19 return {20 json: {21 valid: false,22 errors,23 original: $input.item.json24 }25 };26}2728return {29 json: {30 valid: true,31 ...$input.item.json32 }33};Checkpoint
Try-catch trong Code node quan trọng vì sao? Validation function nên check những gì?
🔧 Practical Patterns
6. Practical Patterns
6.1 Build HTML Email
1const items = $input.all();23// Build table rows from data4const rows = items.map(item => {5 const name = item.json.name;6 const amount = item.json.amount.toLocaleString('vi-VN');7 const status = item.json.status;8 return ' <tr><td>' + name + '</td><td>' + amount + ' ₫</td><td>' + status + '</td></tr>';9}).join('\n');1011// Build full HTML12const header = '<h2>Daily Sales Report</h2>';13const dateStr = new Date().toLocaleDateString('vi-VN');14const tableStart = '<table border="1" cellpadding="8">';15const tableHeader = ' <tr><th>Name</th><th>Amount</th><th>Status</th></tr>';16const tableEnd = '</table>';17const footer = '<p>Total: ' + items.length + ' orders</p>';1819const html = [header, '<p>Date: ' + dateStr + '</p>',20 tableStart, tableHeader, rows, tableEnd, footer].join('\n');2122return [{ json: { html: html, subject: 'Daily Sales Report' } }];6.2 CSV Generation
1const items = $input.all();2const headers = Object.keys(items[0].json);34const csv = [5 headers.join(','),6 ...items.map(item =>7 headers.map(h => '"' + (item.json[h] ?? '') + '"').join(',')8 )9].join('\n');1011return [{ json: { csv, filename: 'report_' + Date.now() + '.csv' } }];6.3 Rate-Limited Batch Processing
1const items = $input.all();2const batchSize = 5;3const delayMs = 1000;4const results = [];56for (let i = 0; i < items.length; i += batchSize) {7 const batch = items.slice(i, i + batchSize);8 9 const batchResults = await Promise.all(10 batch.map(item => processItem(item.json))11 );12 13 results.push(...batchResults);14 15 if (i + batchSize < items.length) {16 await new Promise(resolve => setTimeout(resolve, delayMs));17 }18}1920return results.map(r => ({ json: r }));7. Hands-on Lab
Lab 1: CSV Parser & Transformer
- Webhook — Receive raw CSV text
- Code — Parse CSV, clean data, calculate totals
- Code — Generate summary (groups, averages, top items)
- Slack — Post formatted results
Lab 2: AI-Powered Classifier
- Google Sheets — Get unclassified items
- Code — Call OpenAI API to classify each item
- Code — Aggregate results by classification
- Google Sheets — Update with classifications
Lab 3: HTML Report Generator
- Schedule (end of day)
- HTTP Request — Get day's data from multiple APIs
- Code — Build HTML email with tables, charts, KPIs
- Email — Send to stakeholders
📝 Quiz
-
Code node "Run Once for All Items" khác "Each Item" ở?
- Nhận tất cả items cùng lúc vs từng item
- Không khác nhau
- Speed khác nhau
- Language khác nhau
-
Để return multiple items từ Code node?
- Gọi return nhiều lần
- Return array of json objects (mỗi object có key json)
- Dùng loop node
- Không thể
-
$input.item.jsondùng trong mode nào?- Run Once for Each Item
- Run Once for All Items
- Cả hai
- Không mode nào
🎯 Key Takeaways
- Two modes — "Each Item" for transforms, "All Items" for aggregation
- $input — Access current/all items
- fetch() — Call any API from code
- Return format — Object với key json hoặc array of objects
- Error handling — Always try-catch for production workflows
Checkpoint
Viết Code node tạo HTML email report từ danh sách items. Cần return data ở format nào?
🚀 Bài tiếp theo
Error Handling & Monitoring — Xử lý lỗi và monitoring production workflows!
