bps-kit 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bps-kit.json +4 -4
- package/README.md +3 -0
- package/implementation_plan.md.resolved +37 -0
- package/package.json +2 -2
- package/templates/agents-template/ARCHITECTURE.md +21 -9
- package/templates/agents-template/agents/automation-specialist.md +157 -0
- package/templates/agents-template/rules/GEMINI.md +2 -10
- package/templates/agents-template/workflows/automate.md +153 -0
- package/templates/skills_normal/n8n-code-javascript/BUILTIN_FUNCTIONS.md +764 -0
- package/templates/skills_normal/n8n-code-javascript/COMMON_PATTERNS.md +1110 -0
- package/templates/skills_normal/n8n-code-javascript/DATA_ACCESS.md +782 -0
- package/templates/skills_normal/n8n-code-javascript/ERROR_PATTERNS.md +763 -0
- package/templates/skills_normal/n8n-code-javascript/README.md +350 -0
- package/templates/skills_normal/n8n-code-javascript/SKILL.md +699 -0
- package/templates/skills_normal/n8n-code-python/COMMON_PATTERNS.md +794 -0
- package/templates/skills_normal/n8n-code-python/DATA_ACCESS.md +702 -0
- package/templates/skills_normal/n8n-code-python/ERROR_PATTERNS.md +601 -0
- package/templates/skills_normal/n8n-code-python/README.md +386 -0
- package/templates/skills_normal/n8n-code-python/SKILL.md +748 -0
- package/templates/skills_normal/n8n-code-python/STANDARD_LIBRARY.md +974 -0
- package/templates/skills_normal/n8n-expression-syntax/COMMON_MISTAKES.md +393 -0
- package/templates/skills_normal/n8n-expression-syntax/EXAMPLES.md +483 -0
- package/templates/skills_normal/n8n-expression-syntax/README.md +93 -0
- package/templates/skills_normal/n8n-expression-syntax/SKILL.md +516 -0
- package/templates/skills_normal/n8n-mcp-tools-expert/README.md +99 -0
- package/templates/skills_normal/n8n-mcp-tools-expert/SEARCH_GUIDE.md +374 -0
- package/templates/skills_normal/n8n-mcp-tools-expert/SKILL.md +642 -0
- package/templates/skills_normal/n8n-mcp-tools-expert/VALIDATION_GUIDE.md +442 -0
- package/templates/skills_normal/n8n-mcp-tools-expert/WORKFLOW_GUIDE.md +618 -0
- package/templates/skills_normal/n8n-node-configuration/DEPENDENCIES.md +789 -0
- package/templates/skills_normal/n8n-node-configuration/OPERATION_PATTERNS.md +913 -0
- package/templates/skills_normal/n8n-node-configuration/README.md +364 -0
- package/templates/skills_normal/n8n-node-configuration/SKILL.md +785 -0
- package/templates/skills_normal/n8n-validation-expert/ERROR_CATALOG.md +943 -0
- package/templates/skills_normal/n8n-validation-expert/FALSE_POSITIVES.md +720 -0
- package/templates/skills_normal/n8n-validation-expert/README.md +290 -0
- package/templates/skills_normal/n8n-validation-expert/SKILL.md +689 -0
- package/templates/skills_normal/n8n-workflow-patterns/README.md +251 -0
- package/templates/skills_normal/n8n-workflow-patterns/SKILL.md +411 -0
- package/templates/skills_normal/n8n-workflow-patterns/ai_agent_workflow.md +784 -0
- package/templates/skills_normal/n8n-workflow-patterns/database_operations.md +785 -0
- package/templates/skills_normal/n8n-workflow-patterns/http_api_integration.md +734 -0
- package/templates/skills_normal/n8n-workflow-patterns/scheduled_tasks.md +773 -0
- package/templates/skills_normal/n8n-workflow-patterns/webhook_processing.md +545 -0
- package/templates/vault/n8n-code-javascript/SKILL.md +10 -10
- package/templates/vault/n8n-code-python/SKILL.md +11 -11
- package/templates/vault/n8n-expression-syntax/SKILL.md +4 -4
- package/templates/vault/n8n-mcp-tools-expert/SKILL.md +9 -9
- package/templates/vault/n8n-node-configuration/SKILL.md +2 -2
- package/templates/vault/n8n-validation-expert/SKILL.md +3 -3
- package/templates/vault/n8n-workflow-patterns/SKILL.md +11 -11
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
# Data Access Patterns - JavaScript Code Node
|
|
2
|
+
|
|
3
|
+
Comprehensive guide to accessing data in n8n Code nodes using JavaScript.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
In n8n Code nodes, you access data from previous nodes using built-in variables and methods. Understanding which method to use is critical for correct workflow execution.
|
|
10
|
+
|
|
11
|
+
**Data Access Priority** (by common usage):
|
|
12
|
+
1. **`$input.all()`** - Most common - Batch operations, aggregations
|
|
13
|
+
2. **`$input.first()`** - Very common - Single item operations
|
|
14
|
+
3. **`$input.item`** - Common - Each Item mode only
|
|
15
|
+
4. **`$node["NodeName"].json`** - Specific node references
|
|
16
|
+
5. **`$json`** - Direct current item (legacy, use `$input` instead)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Pattern 1: $input.all() - Process All Items
|
|
21
|
+
|
|
22
|
+
**Usage**: Most common pattern for batch processing
|
|
23
|
+
|
|
24
|
+
**When to use:**
|
|
25
|
+
- Processing multiple records
|
|
26
|
+
- Aggregating data (sum, count, average)
|
|
27
|
+
- Filtering arrays
|
|
28
|
+
- Transforming datasets
|
|
29
|
+
- Comparing items
|
|
30
|
+
- Sorting or ranking
|
|
31
|
+
|
|
32
|
+
### Basic Usage
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// Get all items from previous node
|
|
36
|
+
const allItems = $input.all();
|
|
37
|
+
|
|
38
|
+
// allItems is an array of objects like:
|
|
39
|
+
// [
|
|
40
|
+
// {json: {id: 1, name: "Alice"}},
|
|
41
|
+
// {json: {id: 2, name: "Bob"}}
|
|
42
|
+
// ]
|
|
43
|
+
|
|
44
|
+
console.log(`Received ${allItems.length} items`);
|
|
45
|
+
|
|
46
|
+
return allItems;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Example 1: Filter Active Items
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const allItems = $input.all();
|
|
53
|
+
|
|
54
|
+
// Filter only active items
|
|
55
|
+
const activeItems = allItems.filter(item => item.json.status === 'active');
|
|
56
|
+
|
|
57
|
+
return activeItems;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Example 2: Transform All Items
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
const allItems = $input.all();
|
|
64
|
+
|
|
65
|
+
// Map to new structure
|
|
66
|
+
const transformed = allItems.map(item => ({
|
|
67
|
+
json: {
|
|
68
|
+
id: item.json.id,
|
|
69
|
+
fullName: `${item.json.firstName} ${item.json.lastName}`,
|
|
70
|
+
email: item.json.email,
|
|
71
|
+
processedAt: new Date().toISOString()
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
return transformed;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Example 3: Aggregate Data
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const allItems = $input.all();
|
|
82
|
+
|
|
83
|
+
// Calculate total
|
|
84
|
+
const total = allItems.reduce((sum, item) => {
|
|
85
|
+
return sum + (item.json.amount || 0);
|
|
86
|
+
}, 0);
|
|
87
|
+
|
|
88
|
+
return [{
|
|
89
|
+
json: {
|
|
90
|
+
total,
|
|
91
|
+
count: allItems.length,
|
|
92
|
+
average: total / allItems.length
|
|
93
|
+
}
|
|
94
|
+
}];
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Example 4: Sort and Limit
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const allItems = $input.all();
|
|
101
|
+
|
|
102
|
+
// Get top 5 by score
|
|
103
|
+
const topFive = allItems
|
|
104
|
+
.sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
|
|
105
|
+
.slice(0, 5);
|
|
106
|
+
|
|
107
|
+
return topFive.map(item => ({json: item.json}));
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Example 5: Group By Category
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
const allItems = $input.all();
|
|
114
|
+
|
|
115
|
+
// Group items by category
|
|
116
|
+
const grouped = {};
|
|
117
|
+
|
|
118
|
+
for (const item of allItems) {
|
|
119
|
+
const category = item.json.category || 'Uncategorized';
|
|
120
|
+
|
|
121
|
+
if (!grouped[category]) {
|
|
122
|
+
grouped[category] = [];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
grouped[category].push(item.json);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Convert to array format
|
|
129
|
+
return Object.entries(grouped).map(([category, items]) => ({
|
|
130
|
+
json: {
|
|
131
|
+
category,
|
|
132
|
+
items,
|
|
133
|
+
count: items.length
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Example 6: Deduplicate by ID
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
const allItems = $input.all();
|
|
142
|
+
|
|
143
|
+
// Remove duplicates by ID
|
|
144
|
+
const seen = new Set();
|
|
145
|
+
const unique = [];
|
|
146
|
+
|
|
147
|
+
for (const item of allItems) {
|
|
148
|
+
const id = item.json.id;
|
|
149
|
+
|
|
150
|
+
if (!seen.has(id)) {
|
|
151
|
+
seen.add(id);
|
|
152
|
+
unique.push(item);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return unique;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Pattern 2: $input.first() - Get First Item
|
|
162
|
+
|
|
163
|
+
**Usage**: Very common for single-item operations
|
|
164
|
+
|
|
165
|
+
**When to use:**
|
|
166
|
+
- Previous node returns single object
|
|
167
|
+
- Working with API responses
|
|
168
|
+
- Getting initial/first data point
|
|
169
|
+
- Configuration or metadata access
|
|
170
|
+
|
|
171
|
+
### Basic Usage
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// Get first item from previous node
|
|
175
|
+
const firstItem = $input.first();
|
|
176
|
+
|
|
177
|
+
// Access the JSON data
|
|
178
|
+
const data = firstItem.json;
|
|
179
|
+
|
|
180
|
+
console.log('First item:', data);
|
|
181
|
+
|
|
182
|
+
return [{json: data}];
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Example 1: Process Single API Response
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// Get API response (typically single object)
|
|
189
|
+
const response = $input.first().json;
|
|
190
|
+
|
|
191
|
+
// Extract what you need
|
|
192
|
+
return [{
|
|
193
|
+
json: {
|
|
194
|
+
userId: response.data.user.id,
|
|
195
|
+
userName: response.data.user.name,
|
|
196
|
+
status: response.status,
|
|
197
|
+
fetchedAt: new Date().toISOString()
|
|
198
|
+
}
|
|
199
|
+
}];
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Example 2: Transform Single Object
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
const data = $input.first().json;
|
|
206
|
+
|
|
207
|
+
// Transform structure
|
|
208
|
+
return [{
|
|
209
|
+
json: {
|
|
210
|
+
id: data.id,
|
|
211
|
+
contact: {
|
|
212
|
+
email: data.email,
|
|
213
|
+
phone: data.phone
|
|
214
|
+
},
|
|
215
|
+
address: {
|
|
216
|
+
street: data.street,
|
|
217
|
+
city: data.city,
|
|
218
|
+
zip: data.zip
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}];
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Example 3: Validate Single Item
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const item = $input.first().json;
|
|
228
|
+
|
|
229
|
+
// Validation logic
|
|
230
|
+
const isValid = item.email && item.email.includes('@');
|
|
231
|
+
|
|
232
|
+
return [{
|
|
233
|
+
json: {
|
|
234
|
+
...item,
|
|
235
|
+
valid: isValid,
|
|
236
|
+
validatedAt: new Date().toISOString()
|
|
237
|
+
}
|
|
238
|
+
}];
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Example 4: Extract Nested Data
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
const response = $input.first().json;
|
|
245
|
+
|
|
246
|
+
// Navigate nested structure
|
|
247
|
+
const users = response.data?.users || [];
|
|
248
|
+
|
|
249
|
+
return users.map(user => ({
|
|
250
|
+
json: {
|
|
251
|
+
id: user.id,
|
|
252
|
+
name: user.profile?.name || 'Unknown',
|
|
253
|
+
email: user.contact?.email || 'no-email'
|
|
254
|
+
}
|
|
255
|
+
}));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Example 5: Combine with Other Methods
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
// Get first item's data
|
|
262
|
+
const firstData = $input.first().json;
|
|
263
|
+
|
|
264
|
+
// Use it to filter all items
|
|
265
|
+
const allItems = $input.all();
|
|
266
|
+
const matching = allItems.filter(item =>
|
|
267
|
+
item.json.category === firstData.targetCategory
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
return matching;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Pattern 3: $input.item - Current Item (Each Item Mode)
|
|
276
|
+
|
|
277
|
+
**Usage**: Common in "Run Once for Each Item" mode
|
|
278
|
+
|
|
279
|
+
**When to use:**
|
|
280
|
+
- Mode is set to "Run Once for Each Item"
|
|
281
|
+
- Need to process items independently
|
|
282
|
+
- Per-item API calls or validations
|
|
283
|
+
- Item-specific error handling
|
|
284
|
+
|
|
285
|
+
**IMPORTANT**: Only use in "Each Item" mode. Will be undefined in "All Items" mode.
|
|
286
|
+
|
|
287
|
+
### Basic Usage
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
// In "Run Once for Each Item" mode
|
|
291
|
+
const currentItem = $input.item;
|
|
292
|
+
const data = currentItem.json;
|
|
293
|
+
|
|
294
|
+
console.log('Processing item:', data.id);
|
|
295
|
+
|
|
296
|
+
return [{
|
|
297
|
+
json: {
|
|
298
|
+
...data,
|
|
299
|
+
processed: true
|
|
300
|
+
}
|
|
301
|
+
}];
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Example 1: Add Processing Metadata
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
const item = $input.item;
|
|
308
|
+
|
|
309
|
+
return [{
|
|
310
|
+
json: {
|
|
311
|
+
...item.json,
|
|
312
|
+
processed: true,
|
|
313
|
+
processedAt: new Date().toISOString(),
|
|
314
|
+
processingDuration: Math.random() * 1000 // Simulated duration
|
|
315
|
+
}
|
|
316
|
+
}];
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Example 2: Per-Item Validation
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
const item = $input.item;
|
|
323
|
+
const data = item.json;
|
|
324
|
+
|
|
325
|
+
// Validate this specific item
|
|
326
|
+
const errors = [];
|
|
327
|
+
|
|
328
|
+
if (!data.email) errors.push('Email required');
|
|
329
|
+
if (!data.name) errors.push('Name required');
|
|
330
|
+
if (data.age && data.age < 18) errors.push('Must be 18+');
|
|
331
|
+
|
|
332
|
+
return [{
|
|
333
|
+
json: {
|
|
334
|
+
...data,
|
|
335
|
+
valid: errors.length === 0,
|
|
336
|
+
errors: errors.length > 0 ? errors : undefined
|
|
337
|
+
}
|
|
338
|
+
}];
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Example 3: Item-Specific API Call
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
const item = $input.item;
|
|
345
|
+
const userId = item.json.userId;
|
|
346
|
+
|
|
347
|
+
// Make API call specific to this item
|
|
348
|
+
const response = await $helpers.httpRequest({
|
|
349
|
+
method: 'GET',
|
|
350
|
+
url: `https://api.example.com/users/${userId}/details`
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
return [{
|
|
354
|
+
json: {
|
|
355
|
+
...item.json,
|
|
356
|
+
details: response
|
|
357
|
+
}
|
|
358
|
+
}];
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Example 4: Conditional Processing
|
|
362
|
+
|
|
363
|
+
```javascript
|
|
364
|
+
const item = $input.item;
|
|
365
|
+
const data = item.json;
|
|
366
|
+
|
|
367
|
+
// Process based on item type
|
|
368
|
+
if (data.type === 'premium') {
|
|
369
|
+
return [{
|
|
370
|
+
json: {
|
|
371
|
+
...data,
|
|
372
|
+
discount: 0.20,
|
|
373
|
+
tier: 'premium'
|
|
374
|
+
}
|
|
375
|
+
}];
|
|
376
|
+
} else {
|
|
377
|
+
return [{
|
|
378
|
+
json: {
|
|
379
|
+
...data,
|
|
380
|
+
discount: 0.05,
|
|
381
|
+
tier: 'standard'
|
|
382
|
+
}
|
|
383
|
+
}];
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Pattern 4: $node - Reference Other Nodes
|
|
390
|
+
|
|
391
|
+
**Usage**: Less common, but powerful for specific scenarios
|
|
392
|
+
|
|
393
|
+
**When to use:**
|
|
394
|
+
- Need data from specific named node
|
|
395
|
+
- Combining data from multiple nodes
|
|
396
|
+
- Accessing metadata about workflow execution
|
|
397
|
+
|
|
398
|
+
### Basic Usage
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
// Get output from specific node
|
|
402
|
+
const webhookData = $node["Webhook"].json;
|
|
403
|
+
const apiData = $node["HTTP Request"].json;
|
|
404
|
+
|
|
405
|
+
return [{
|
|
406
|
+
json: {
|
|
407
|
+
fromWebhook: webhookData,
|
|
408
|
+
fromAPI: apiData
|
|
409
|
+
}
|
|
410
|
+
}];
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Example 1: Combine Multiple Sources
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// Reference multiple nodes
|
|
417
|
+
const webhook = $node["Webhook"].json;
|
|
418
|
+
const database = $node["Postgres"].json;
|
|
419
|
+
const api = $node["HTTP Request"].json;
|
|
420
|
+
|
|
421
|
+
return [{
|
|
422
|
+
json: {
|
|
423
|
+
combined: {
|
|
424
|
+
webhook: webhook.body,
|
|
425
|
+
dbRecords: database.length,
|
|
426
|
+
apiResponse: api.status
|
|
427
|
+
},
|
|
428
|
+
processedAt: new Date().toISOString()
|
|
429
|
+
}
|
|
430
|
+
}];
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Example 2: Compare Across Nodes
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
const oldData = $node["Get Old Data"].json;
|
|
437
|
+
const newData = $node["Get New Data"].json;
|
|
438
|
+
|
|
439
|
+
// Compare
|
|
440
|
+
const changes = {
|
|
441
|
+
added: newData.filter(n => !oldData.find(o => o.id === n.id)),
|
|
442
|
+
removed: oldData.filter(o => !newData.find(n => n.id === o.id)),
|
|
443
|
+
modified: newData.filter(n => {
|
|
444
|
+
const old = oldData.find(o => o.id === n.id);
|
|
445
|
+
return old && JSON.stringify(old) !== JSON.stringify(n);
|
|
446
|
+
})
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
return [{
|
|
450
|
+
json: {
|
|
451
|
+
changes,
|
|
452
|
+
summary: {
|
|
453
|
+
added: changes.added.length,
|
|
454
|
+
removed: changes.removed.length,
|
|
455
|
+
modified: changes.modified.length
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}];
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Example 3: Access Node Metadata
|
|
462
|
+
|
|
463
|
+
```javascript
|
|
464
|
+
// Get data from specific execution path
|
|
465
|
+
const ifTrueBranch = $node["IF True"].json;
|
|
466
|
+
const ifFalseBranch = $node["IF False"].json;
|
|
467
|
+
|
|
468
|
+
// Use whichever branch executed
|
|
469
|
+
const result = ifTrueBranch || ifFalseBranch || {};
|
|
470
|
+
|
|
471
|
+
return [{json: result}];
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Critical: Webhook Data Structure
|
|
477
|
+
|
|
478
|
+
**MOST COMMON MISTAKE**: Forgetting webhook data is nested under `.body`
|
|
479
|
+
|
|
480
|
+
### The Problem
|
|
481
|
+
|
|
482
|
+
Webhook node wraps all incoming data under a `body` property. This catches many developers by surprise.
|
|
483
|
+
|
|
484
|
+
### Structure
|
|
485
|
+
|
|
486
|
+
```javascript
|
|
487
|
+
// Webhook node output structure:
|
|
488
|
+
{
|
|
489
|
+
"headers": {
|
|
490
|
+
"content-type": "application/json",
|
|
491
|
+
"user-agent": "...",
|
|
492
|
+
// ... other headers
|
|
493
|
+
},
|
|
494
|
+
"params": {},
|
|
495
|
+
"query": {},
|
|
496
|
+
"body": {
|
|
497
|
+
// ← YOUR DATA IS HERE
|
|
498
|
+
"name": "Alice",
|
|
499
|
+
"email": "alice@example.com",
|
|
500
|
+
"message": "Hello!"
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Wrong vs Right
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
// ❌ WRONG: Trying to access directly
|
|
509
|
+
const name = $json.name; // undefined
|
|
510
|
+
const email = $json.email; // undefined
|
|
511
|
+
|
|
512
|
+
// ✅ CORRECT: Access via .body
|
|
513
|
+
const name = $json.body.name; // "Alice"
|
|
514
|
+
const email = $json.body.email; // "alice@example.com"
|
|
515
|
+
|
|
516
|
+
// ✅ CORRECT: Extract body first
|
|
517
|
+
const webhookData = $json.body;
|
|
518
|
+
const name = webhookData.name; // "Alice"
|
|
519
|
+
const email = webhookData.email; // "alice@example.com"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Example: Full Webhook Processing
|
|
523
|
+
|
|
524
|
+
```javascript
|
|
525
|
+
// Get webhook data from previous node
|
|
526
|
+
const webhookOutput = $input.first().json;
|
|
527
|
+
|
|
528
|
+
// Access the actual payload
|
|
529
|
+
const payload = webhookOutput.body;
|
|
530
|
+
|
|
531
|
+
// Access headers if needed
|
|
532
|
+
const contentType = webhookOutput.headers['content-type'];
|
|
533
|
+
|
|
534
|
+
// Access query parameters if needed
|
|
535
|
+
const apiKey = webhookOutput.query.api_key;
|
|
536
|
+
|
|
537
|
+
// Process the actual data
|
|
538
|
+
return [{
|
|
539
|
+
json: {
|
|
540
|
+
// Data from webhook body
|
|
541
|
+
userName: payload.name,
|
|
542
|
+
userEmail: payload.email,
|
|
543
|
+
message: payload.message,
|
|
544
|
+
|
|
545
|
+
// Metadata
|
|
546
|
+
receivedAt: new Date().toISOString(),
|
|
547
|
+
contentType: contentType,
|
|
548
|
+
authenticated: !!apiKey
|
|
549
|
+
}
|
|
550
|
+
}];
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### POST Data, Query Params, and Headers
|
|
554
|
+
|
|
555
|
+
```javascript
|
|
556
|
+
const webhook = $input.first().json;
|
|
557
|
+
|
|
558
|
+
return [{
|
|
559
|
+
json: {
|
|
560
|
+
// POST body data
|
|
561
|
+
formData: webhook.body,
|
|
562
|
+
|
|
563
|
+
// Query parameters (?key=value)
|
|
564
|
+
queryParams: webhook.query,
|
|
565
|
+
|
|
566
|
+
// HTTP headers
|
|
567
|
+
userAgent: webhook.headers['user-agent'],
|
|
568
|
+
contentType: webhook.headers['content-type'],
|
|
569
|
+
|
|
570
|
+
// Request metadata
|
|
571
|
+
method: webhook.method, // POST, GET, etc.
|
|
572
|
+
url: webhook.url
|
|
573
|
+
}
|
|
574
|
+
}];
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### Common Webhook Scenarios
|
|
578
|
+
|
|
579
|
+
```javascript
|
|
580
|
+
// Scenario 1: Form submission
|
|
581
|
+
const formData = $json.body;
|
|
582
|
+
const name = formData.name;
|
|
583
|
+
const email = formData.email;
|
|
584
|
+
|
|
585
|
+
// Scenario 2: JSON API webhook
|
|
586
|
+
const apiPayload = $json.body;
|
|
587
|
+
const eventType = apiPayload.event;
|
|
588
|
+
const data = apiPayload.data;
|
|
589
|
+
|
|
590
|
+
// Scenario 3: Query parameters
|
|
591
|
+
const apiKey = $json.query.api_key;
|
|
592
|
+
const userId = $json.query.user_id;
|
|
593
|
+
|
|
594
|
+
// Scenario 4: Headers
|
|
595
|
+
const authorization = $json.headers['authorization'];
|
|
596
|
+
const signature = $json.headers['x-signature'];
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Choosing the Right Pattern
|
|
602
|
+
|
|
603
|
+
### Decision Tree
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
Do you need ALL items from previous node?
|
|
607
|
+
├─ YES → Use $input.all()
|
|
608
|
+
│
|
|
609
|
+
└─ NO → Do you need just the FIRST item?
|
|
610
|
+
├─ YES → Use $input.first()
|
|
611
|
+
│
|
|
612
|
+
└─ NO → Are you in "Each Item" mode?
|
|
613
|
+
├─ YES → Use $input.item
|
|
614
|
+
│
|
|
615
|
+
└─ NO → Do you need specific node data?
|
|
616
|
+
├─ YES → Use $node["NodeName"]
|
|
617
|
+
└─ NO → Use $input.first() (default)
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Quick Reference Table
|
|
621
|
+
|
|
622
|
+
| Scenario | Use This | Example |
|
|
623
|
+
|----------|----------|---------|
|
|
624
|
+
| Sum all amounts | `$input.all()` | `allItems.reduce((sum, i) => sum + i.json.amount, 0)` |
|
|
625
|
+
| Get API response | `$input.first()` | `$input.first().json.data` |
|
|
626
|
+
| Process each independently | `$input.item` | `$input.item.json` (Each Item mode) |
|
|
627
|
+
| Combine two nodes | `$node["Name"]` | `$node["API"].json` |
|
|
628
|
+
| Filter array | `$input.all()` | `allItems.filter(i => i.json.active)` |
|
|
629
|
+
| Transform single object | `$input.first()` | `{...input.first().json, new: true}` |
|
|
630
|
+
| Webhook data | `$input.first()` | `$input.first().json.body` |
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Common Mistakes
|
|
635
|
+
|
|
636
|
+
### Mistake 1: Using $json Without Context
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
// ❌ WRONG: $json is ambiguous
|
|
640
|
+
const value = $json.field;
|
|
641
|
+
|
|
642
|
+
// ✅ CORRECT: Be explicit
|
|
643
|
+
const value = $input.first().json.field;
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### Mistake 2: Forgetting .json Property
|
|
647
|
+
|
|
648
|
+
```javascript
|
|
649
|
+
// ❌ WRONG: Trying to access fields on item object
|
|
650
|
+
const items = $input.all();
|
|
651
|
+
const names = items.map(item => item.name); // undefined
|
|
652
|
+
|
|
653
|
+
// ✅ CORRECT: Access via .json
|
|
654
|
+
const names = items.map(item => item.json.name);
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Mistake 3: Using $input.item in All Items Mode
|
|
658
|
+
|
|
659
|
+
```javascript
|
|
660
|
+
// ❌ WRONG: $input.item is undefined in "All Items" mode
|
|
661
|
+
const data = $input.item.json; // Error!
|
|
662
|
+
|
|
663
|
+
// ✅ CORRECT: Use appropriate method
|
|
664
|
+
const data = $input.first().json; // Or $input.all()
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Mistake 4: Not Handling Empty Arrays
|
|
668
|
+
|
|
669
|
+
```javascript
|
|
670
|
+
// ❌ WRONG: Crashes if no items
|
|
671
|
+
const first = $input.all()[0].json;
|
|
672
|
+
|
|
673
|
+
// ✅ CORRECT: Check length first
|
|
674
|
+
const items = $input.all();
|
|
675
|
+
if (items.length === 0) {
|
|
676
|
+
return [];
|
|
677
|
+
}
|
|
678
|
+
const first = items[0].json;
|
|
679
|
+
|
|
680
|
+
// ✅ ALSO CORRECT: Use $input.first()
|
|
681
|
+
const first = $input.first().json; // Built-in safety
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Mistake 5: Modifying Original Data
|
|
685
|
+
|
|
686
|
+
```javascript
|
|
687
|
+
// ❌ RISKY: Mutating original
|
|
688
|
+
const items = $input.all();
|
|
689
|
+
items[0].json.modified = true; // Modifies original
|
|
690
|
+
return items;
|
|
691
|
+
|
|
692
|
+
// ✅ SAFE: Create new objects
|
|
693
|
+
const items = $input.all();
|
|
694
|
+
return items.map(item => ({
|
|
695
|
+
json: {
|
|
696
|
+
...item.json,
|
|
697
|
+
modified: true
|
|
698
|
+
}
|
|
699
|
+
}));
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## Advanced Patterns
|
|
705
|
+
|
|
706
|
+
### Pattern: Pagination Handling
|
|
707
|
+
|
|
708
|
+
```javascript
|
|
709
|
+
const currentPage = $input.all();
|
|
710
|
+
const pageNumber = $node["Set Page"].json.page || 1;
|
|
711
|
+
|
|
712
|
+
// Combine with previous pages
|
|
713
|
+
const allPreviousPages = $node["Accumulator"]?.json.accumulated || [];
|
|
714
|
+
|
|
715
|
+
return [{
|
|
716
|
+
json: {
|
|
717
|
+
accumulated: [...allPreviousPages, ...currentPage],
|
|
718
|
+
currentPage: pageNumber,
|
|
719
|
+
totalItems: allPreviousPages.length + currentPage.length
|
|
720
|
+
}
|
|
721
|
+
}];
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### Pattern: Conditional Node Reference
|
|
725
|
+
|
|
726
|
+
```javascript
|
|
727
|
+
// Access different nodes based on condition
|
|
728
|
+
const condition = $input.first().json.type;
|
|
729
|
+
|
|
730
|
+
let data;
|
|
731
|
+
if (condition === 'api') {
|
|
732
|
+
data = $node["API Response"].json;
|
|
733
|
+
} else if (condition === 'database') {
|
|
734
|
+
data = $node["Database"].json;
|
|
735
|
+
} else {
|
|
736
|
+
data = $node["Default"].json;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return [{json: data}];
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Pattern: Multi-Node Aggregation
|
|
743
|
+
|
|
744
|
+
```javascript
|
|
745
|
+
// Collect data from multiple named nodes
|
|
746
|
+
const sources = ['Source1', 'Source2', 'Source3'];
|
|
747
|
+
const allData = [];
|
|
748
|
+
|
|
749
|
+
for (const source of sources) {
|
|
750
|
+
const nodeData = $node[source]?.json;
|
|
751
|
+
if (nodeData) {
|
|
752
|
+
allData.push({
|
|
753
|
+
source,
|
|
754
|
+
data: nodeData
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return allData.map(item => ({json: item}));
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
## Summary
|
|
765
|
+
|
|
766
|
+
**Most Common Patterns**:
|
|
767
|
+
1. `$input.all()` - Process multiple items, batch operations
|
|
768
|
+
2. `$input.first()` - Single item, API responses
|
|
769
|
+
3. `$input.item` - Each Item mode processing
|
|
770
|
+
|
|
771
|
+
**Critical Rule**:
|
|
772
|
+
- Webhook data is under `.body` property
|
|
773
|
+
|
|
774
|
+
**Best Practice**:
|
|
775
|
+
- Be explicit: Use `$input.first().json.field` instead of `$json.field`
|
|
776
|
+
- Always check for null/undefined
|
|
777
|
+
- Use appropriate method for your mode (All Items vs Each Item)
|
|
778
|
+
|
|
779
|
+
**See Also**:
|
|
780
|
+
- [SKILL.md](SKILL.md) - Overview and quick start
|
|
781
|
+
- [COMMON_PATTERNS.md](COMMON_PATTERNS.md) - Production patterns
|
|
782
|
+
- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) - Avoid common mistakes
|