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,734 @@
|
|
|
1
|
+
# HTTP API Integration Pattern
|
|
2
|
+
|
|
3
|
+
**Use Case**: Fetch data from REST APIs, transform it, and use it in workflows.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pattern Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Trigger → HTTP Request → [Transform] → [Action] → [Error Handler]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Key Characteristic**: External data fetching with error handling
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Components
|
|
18
|
+
|
|
19
|
+
### 1. Trigger
|
|
20
|
+
**Options**:
|
|
21
|
+
- **Schedule** - Periodic fetching (most common)
|
|
22
|
+
- **Webhook** - Triggered by external event
|
|
23
|
+
- **Manual** - On-demand execution
|
|
24
|
+
|
|
25
|
+
### 2. HTTP Request Node
|
|
26
|
+
**Purpose**: Call external REST APIs
|
|
27
|
+
|
|
28
|
+
**Configuration**:
|
|
29
|
+
```javascript
|
|
30
|
+
{
|
|
31
|
+
method: "GET", // GET, POST, PUT, DELETE, PATCH
|
|
32
|
+
url: "https://api.example.com/users",
|
|
33
|
+
authentication: "predefinedCredentialType",
|
|
34
|
+
sendQuery: true,
|
|
35
|
+
queryParameters: {
|
|
36
|
+
"page": "={{$json.page}}",
|
|
37
|
+
"limit": "100"
|
|
38
|
+
},
|
|
39
|
+
sendHeaders: true,
|
|
40
|
+
headerParameters: {
|
|
41
|
+
"Accept": "application/json",
|
|
42
|
+
"X-API-Version": "v1"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Response Processing
|
|
48
|
+
**Purpose**: Extract and transform API response data
|
|
49
|
+
|
|
50
|
+
**Typical flow**:
|
|
51
|
+
```
|
|
52
|
+
HTTP Request → Code (parse) → Set (map fields) → Action
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 4. Action
|
|
56
|
+
**Common actions**:
|
|
57
|
+
- Store in database
|
|
58
|
+
- Send to another API
|
|
59
|
+
- Create notifications
|
|
60
|
+
- Update spreadsheet
|
|
61
|
+
|
|
62
|
+
### 5. Error Handler
|
|
63
|
+
**Purpose**: Handle API failures gracefully
|
|
64
|
+
|
|
65
|
+
**Error Trigger Workflow**:
|
|
66
|
+
```
|
|
67
|
+
Error Trigger → Log Error → Notify Admin → Retry Logic (optional)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Common Use Cases
|
|
73
|
+
|
|
74
|
+
### 1. Data Fetching & Storage
|
|
75
|
+
**Flow**: Schedule → HTTP Request → Transform → Database
|
|
76
|
+
|
|
77
|
+
**Example** (Fetch GitHub issues):
|
|
78
|
+
```
|
|
79
|
+
1. Schedule (every hour)
|
|
80
|
+
2. HTTP Request
|
|
81
|
+
- Method: GET
|
|
82
|
+
- URL: https://api.github.com/repos/owner/repo/issues
|
|
83
|
+
- Auth: Bearer Token
|
|
84
|
+
- Query: state=open
|
|
85
|
+
3. Code (filter by labels)
|
|
86
|
+
4. Set (map to database schema)
|
|
87
|
+
5. Postgres (upsert issues)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Response Handling**:
|
|
91
|
+
```javascript
|
|
92
|
+
// Code node - filter issues
|
|
93
|
+
const issues = $input.all();
|
|
94
|
+
return issues
|
|
95
|
+
.filter(item => item.json.labels.some(l => l.name === 'bug'))
|
|
96
|
+
.map(item => ({
|
|
97
|
+
json: {
|
|
98
|
+
id: item.json.id,
|
|
99
|
+
title: item.json.title,
|
|
100
|
+
created_at: item.json.created_at
|
|
101
|
+
}
|
|
102
|
+
}));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. API to API Integration
|
|
106
|
+
**Flow**: Trigger → Fetch from API A → Transform → Send to API B
|
|
107
|
+
|
|
108
|
+
**Example** (Jira to Slack):
|
|
109
|
+
```
|
|
110
|
+
1. Schedule (every 15 minutes)
|
|
111
|
+
2. HTTP Request (GET Jira tickets updated today)
|
|
112
|
+
3. IF (check if tickets exist)
|
|
113
|
+
4. Set (format for Slack)
|
|
114
|
+
5. HTTP Request (POST to Slack webhook)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. Data Enrichment
|
|
118
|
+
**Flow**: Trigger → Fetch base data → Call enrichment API → Combine → Store
|
|
119
|
+
|
|
120
|
+
**Example** (Enrich contacts with company data):
|
|
121
|
+
```
|
|
122
|
+
1. Postgres (SELECT new contacts)
|
|
123
|
+
2. Code (extract company domains)
|
|
124
|
+
3. HTTP Request (call Clearbit API for each domain)
|
|
125
|
+
4. Set (combine contact + company data)
|
|
126
|
+
5. Postgres (UPDATE contacts with enrichment)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 4. Monitoring & Alerting
|
|
130
|
+
**Flow**: Schedule → Check API health → IF unhealthy → Alert
|
|
131
|
+
|
|
132
|
+
**Example** (API health check):
|
|
133
|
+
```
|
|
134
|
+
1. Schedule (every 5 minutes)
|
|
135
|
+
2. HTTP Request (GET /health endpoint)
|
|
136
|
+
3. IF (status !== 200 OR response time > 2000ms)
|
|
137
|
+
4. Slack (alert #ops-team)
|
|
138
|
+
5. PagerDuty (create incident)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. Batch Processing
|
|
142
|
+
**Flow**: Trigger → Fetch large dataset → Split in Batches → Process → Loop
|
|
143
|
+
|
|
144
|
+
**Example** (Process all users):
|
|
145
|
+
```
|
|
146
|
+
1. Manual Trigger
|
|
147
|
+
2. HTTP Request (GET /api/users?limit=1000)
|
|
148
|
+
3. Split In Batches (100 items per batch)
|
|
149
|
+
4. HTTP Request (POST /api/process for each batch)
|
|
150
|
+
5. Wait (2 seconds between batches - rate limiting)
|
|
151
|
+
6. Loop (back to step 4 until all processed)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Authentication Methods
|
|
157
|
+
|
|
158
|
+
### 1. None (Public APIs)
|
|
159
|
+
```javascript
|
|
160
|
+
{
|
|
161
|
+
authentication: "none"
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2. Bearer Token (Most Common)
|
|
166
|
+
**Setup**: Create credential
|
|
167
|
+
```javascript
|
|
168
|
+
{
|
|
169
|
+
authentication: "predefinedCredentialType",
|
|
170
|
+
nodeCredentialType: "httpHeaderAuth",
|
|
171
|
+
headerAuth: {
|
|
172
|
+
name: "Authorization",
|
|
173
|
+
value: "Bearer YOUR_TOKEN"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Access in workflow**:
|
|
179
|
+
```javascript
|
|
180
|
+
{
|
|
181
|
+
authentication: "predefinedCredentialType",
|
|
182
|
+
nodeCredentialType: "httpHeaderAuth"
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 3. API Key (Header or Query)
|
|
187
|
+
**Header auth**:
|
|
188
|
+
```javascript
|
|
189
|
+
{
|
|
190
|
+
sendHeaders: true,
|
|
191
|
+
headerParameters: {
|
|
192
|
+
"X-API-Key": "={{$credentials.apiKey}}"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Query auth**:
|
|
198
|
+
```javascript
|
|
199
|
+
{
|
|
200
|
+
sendQuery: true,
|
|
201
|
+
queryParameters: {
|
|
202
|
+
"api_key": "={{$credentials.apiKey}}"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 4. Basic Auth
|
|
208
|
+
**Setup**: Create "Basic Auth" credential
|
|
209
|
+
```javascript
|
|
210
|
+
{
|
|
211
|
+
authentication: "predefinedCredentialType",
|
|
212
|
+
nodeCredentialType: "httpBasicAuth"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 5. OAuth2
|
|
217
|
+
**Setup**: Create OAuth2 credential with:
|
|
218
|
+
- Authorization URL
|
|
219
|
+
- Token URL
|
|
220
|
+
- Client ID
|
|
221
|
+
- Client Secret
|
|
222
|
+
- Scopes
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
{
|
|
226
|
+
authentication: "predefinedCredentialType",
|
|
227
|
+
nodeCredentialType: "oAuth2Api"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Handling API Responses
|
|
234
|
+
|
|
235
|
+
### Success Response (200-299)
|
|
236
|
+
**Default**: Data flows to next node
|
|
237
|
+
|
|
238
|
+
**Access response**:
|
|
239
|
+
```javascript
|
|
240
|
+
// Entire response
|
|
241
|
+
{{$json}}
|
|
242
|
+
|
|
243
|
+
// Specific fields
|
|
244
|
+
{{$json.data.id}}
|
|
245
|
+
{{$json.results[0].name}}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Pagination
|
|
249
|
+
|
|
250
|
+
#### Pattern 1: Offset-based
|
|
251
|
+
```
|
|
252
|
+
1. Set (initialize: page=1, has_more=true)
|
|
253
|
+
2. HTTP Request (GET /api/items?page={{$json.page}})
|
|
254
|
+
3. Code (check if more pages)
|
|
255
|
+
4. IF (has_more === true)
|
|
256
|
+
└→ Set (increment page) → Loop to step 2
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Code node** (check pagination):
|
|
260
|
+
```javascript
|
|
261
|
+
const items = $input.first().json;
|
|
262
|
+
const currentPage = $json.page || 1;
|
|
263
|
+
|
|
264
|
+
return [{
|
|
265
|
+
json: {
|
|
266
|
+
items: items.results,
|
|
267
|
+
page: currentPage + 1,
|
|
268
|
+
has_more: items.next !== null
|
|
269
|
+
}
|
|
270
|
+
}];
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Pattern 2: Cursor-based
|
|
274
|
+
```
|
|
275
|
+
1. HTTP Request (GET /api/items)
|
|
276
|
+
2. Code (extract next_cursor)
|
|
277
|
+
3. IF (next_cursor exists)
|
|
278
|
+
└→ Set (cursor={{$json.next_cursor}}) → Loop to step 1
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Pattern 3: Link Header
|
|
282
|
+
```javascript
|
|
283
|
+
// Code node - parse Link header
|
|
284
|
+
const linkHeader = $input.first().json.headers['link'];
|
|
285
|
+
const hasNext = linkHeader && linkHeader.includes('rel="next"');
|
|
286
|
+
|
|
287
|
+
return [{
|
|
288
|
+
json: {
|
|
289
|
+
items: $input.first().json.body,
|
|
290
|
+
has_next: hasNext,
|
|
291
|
+
next_url: hasNext ? parseNextUrl(linkHeader) : null
|
|
292
|
+
}
|
|
293
|
+
}];
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Error Responses (400-599)
|
|
297
|
+
|
|
298
|
+
**Configure HTTP Request**:
|
|
299
|
+
```javascript
|
|
300
|
+
{
|
|
301
|
+
continueOnFail: true, // Don't stop workflow on error
|
|
302
|
+
ignoreResponseCode: true // Get response even on error
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Handle errors**:
|
|
307
|
+
```
|
|
308
|
+
HTTP Request (continueOnFail: true)
|
|
309
|
+
→ IF (check error)
|
|
310
|
+
├─ [Success Path]
|
|
311
|
+
└─ [Error Path] → Log → Retry or Alert
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**IF condition**:
|
|
315
|
+
```javascript
|
|
316
|
+
{{$json.error}} is empty
|
|
317
|
+
// OR
|
|
318
|
+
{{$json.statusCode}} < 400
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Rate Limiting
|
|
324
|
+
|
|
325
|
+
### Pattern 1: Wait Between Requests
|
|
326
|
+
```
|
|
327
|
+
Split In Batches (1 item per batch)
|
|
328
|
+
→ HTTP Request
|
|
329
|
+
→ Wait (1 second)
|
|
330
|
+
→ Loop
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Pattern 2: Exponential Backoff
|
|
334
|
+
```javascript
|
|
335
|
+
// Code node
|
|
336
|
+
const maxRetries = 3;
|
|
337
|
+
let retryCount = $json.retryCount || 0;
|
|
338
|
+
|
|
339
|
+
if ($json.error && retryCount < maxRetries) {
|
|
340
|
+
const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s
|
|
341
|
+
|
|
342
|
+
return [{
|
|
343
|
+
json: {
|
|
344
|
+
...$json,
|
|
345
|
+
retryCount: retryCount + 1,
|
|
346
|
+
waitTime: delay
|
|
347
|
+
}
|
|
348
|
+
}];
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Pattern 3: Respect Rate Limit Headers
|
|
353
|
+
```javascript
|
|
354
|
+
// Code node - check rate limit
|
|
355
|
+
const headers = $input.first().json.headers;
|
|
356
|
+
const remaining = parseInt(headers['x-ratelimit-remaining'] || '999');
|
|
357
|
+
const resetTime = parseInt(headers['x-ratelimit-reset'] || '0');
|
|
358
|
+
|
|
359
|
+
if (remaining < 10) {
|
|
360
|
+
const now = Math.floor(Date.now() / 1000);
|
|
361
|
+
const waitSeconds = resetTime - now;
|
|
362
|
+
|
|
363
|
+
return [{
|
|
364
|
+
json: {
|
|
365
|
+
shouldWait: true,
|
|
366
|
+
waitSeconds: Math.max(waitSeconds, 0)
|
|
367
|
+
}
|
|
368
|
+
}];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return [{ json: { shouldWait: false } }];
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Request Configuration
|
|
377
|
+
|
|
378
|
+
### GET Request
|
|
379
|
+
```javascript
|
|
380
|
+
{
|
|
381
|
+
method: "GET",
|
|
382
|
+
url: "https://api.example.com/users",
|
|
383
|
+
sendQuery: true,
|
|
384
|
+
queryParameters: {
|
|
385
|
+
"page": "1",
|
|
386
|
+
"limit": "100",
|
|
387
|
+
"filter": "active"
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### POST Request (JSON Body)
|
|
393
|
+
```javascript
|
|
394
|
+
{
|
|
395
|
+
method: "POST",
|
|
396
|
+
url: "https://api.example.com/users",
|
|
397
|
+
sendBody: true,
|
|
398
|
+
bodyParametersJson: JSON.stringify({
|
|
399
|
+
name: "={{$json.name}}",
|
|
400
|
+
email: "={{$json.email}}",
|
|
401
|
+
role: "user"
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### POST Request (Form Data)
|
|
407
|
+
```javascript
|
|
408
|
+
{
|
|
409
|
+
method: "POST",
|
|
410
|
+
url: "https://api.example.com/upload",
|
|
411
|
+
sendBody: true,
|
|
412
|
+
bodyParametersUi: {
|
|
413
|
+
parameter: [
|
|
414
|
+
{ name: "file", value: "={{$json.fileData}}" },
|
|
415
|
+
{ name: "filename", value: "={{$json.filename}}" }
|
|
416
|
+
]
|
|
417
|
+
},
|
|
418
|
+
sendHeaders: true,
|
|
419
|
+
headerParameters: {
|
|
420
|
+
"Content-Type": "multipart/form-data"
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### PUT/PATCH Request (Update)
|
|
426
|
+
```javascript
|
|
427
|
+
{
|
|
428
|
+
method: "PATCH",
|
|
429
|
+
url: "https://api.example.com/users/={{$json.userId}}",
|
|
430
|
+
sendBody: true,
|
|
431
|
+
bodyParametersJson: JSON.stringify({
|
|
432
|
+
status: "active",
|
|
433
|
+
last_updated: "={{$now}}"
|
|
434
|
+
})
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### DELETE Request
|
|
439
|
+
```javascript
|
|
440
|
+
{
|
|
441
|
+
method: "DELETE",
|
|
442
|
+
url: "https://api.example.com/users/={{$json.userId}}"
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Error Handling Patterns
|
|
449
|
+
|
|
450
|
+
### Pattern 1: Retry on Failure
|
|
451
|
+
```
|
|
452
|
+
HTTP Request (continueOnFail: true)
|
|
453
|
+
→ IF (error occurred)
|
|
454
|
+
└→ Wait (5 seconds)
|
|
455
|
+
└→ HTTP Request (retry)
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Pattern 2: Fallback API
|
|
459
|
+
```
|
|
460
|
+
HTTP Request (Primary API, continueOnFail: true)
|
|
461
|
+
→ IF (failed)
|
|
462
|
+
└→ HTTP Request (Fallback API)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Pattern 3: Error Trigger Workflow
|
|
466
|
+
**Main Workflow**:
|
|
467
|
+
```
|
|
468
|
+
HTTP Request → Process Data
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Error Workflow**:
|
|
472
|
+
```
|
|
473
|
+
Error Trigger
|
|
474
|
+
→ Set (extract error details)
|
|
475
|
+
→ Slack (alert team)
|
|
476
|
+
→ Database (log error for analysis)
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Pattern 4: Circuit Breaker
|
|
480
|
+
```javascript
|
|
481
|
+
// Code node - circuit breaker logic
|
|
482
|
+
const failures = $json.recentFailures || 0;
|
|
483
|
+
const threshold = 5;
|
|
484
|
+
|
|
485
|
+
if (failures >= threshold) {
|
|
486
|
+
throw new Error('Circuit breaker open - too many failures');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return [{ json: { canProceed: true } }];
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## Response Transformation
|
|
495
|
+
|
|
496
|
+
### Extract Nested Data
|
|
497
|
+
```javascript
|
|
498
|
+
// Code node
|
|
499
|
+
const response = $input.first().json;
|
|
500
|
+
|
|
501
|
+
return response.data.items.map(item => ({
|
|
502
|
+
json: {
|
|
503
|
+
id: item.id,
|
|
504
|
+
name: item.attributes.name,
|
|
505
|
+
email: item.attributes.contact.email
|
|
506
|
+
}
|
|
507
|
+
}));
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Flatten Arrays
|
|
511
|
+
```javascript
|
|
512
|
+
// Code node - flatten nested array
|
|
513
|
+
const items = $input.all();
|
|
514
|
+
const flattened = items.flatMap(item =>
|
|
515
|
+
item.json.results.map(result => ({
|
|
516
|
+
json: {
|
|
517
|
+
parent_id: item.json.id,
|
|
518
|
+
...result
|
|
519
|
+
}
|
|
520
|
+
}))
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
return flattened;
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Combine Multiple API Responses
|
|
527
|
+
```
|
|
528
|
+
HTTP Request 1 (users)
|
|
529
|
+
→ Set (store users)
|
|
530
|
+
→ HTTP Request 2 (orders for each user)
|
|
531
|
+
→ Merge (combine users + orders)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Testing & Debugging
|
|
537
|
+
|
|
538
|
+
### 1. Test with Manual Trigger
|
|
539
|
+
Replace Schedule with Manual Trigger for testing
|
|
540
|
+
|
|
541
|
+
### 2. Use Postman/Insomnia First
|
|
542
|
+
- Test API outside n8n
|
|
543
|
+
- Understand response structure
|
|
544
|
+
- Verify authentication
|
|
545
|
+
|
|
546
|
+
### 3. Log Responses
|
|
547
|
+
```javascript
|
|
548
|
+
// Code node - log for debugging
|
|
549
|
+
console.log('API Response:', JSON.stringify($input.first().json, null, 2));
|
|
550
|
+
return $input.all();
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### 4. Check Execution Data
|
|
554
|
+
- View node output in n8n UI
|
|
555
|
+
- Check headers, body, status code
|
|
556
|
+
- Verify data structure
|
|
557
|
+
|
|
558
|
+
### 5. Use Binary Data Properly
|
|
559
|
+
For file downloads:
|
|
560
|
+
```javascript
|
|
561
|
+
{
|
|
562
|
+
method: "GET",
|
|
563
|
+
url: "https://api.example.com/download/file.pdf",
|
|
564
|
+
responseFormat: "file", // Important for binary data
|
|
565
|
+
outputPropertyName: "data"
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Performance Optimization
|
|
572
|
+
|
|
573
|
+
### 1. Parallel Requests
|
|
574
|
+
Use **Split In Batches** with multiple items:
|
|
575
|
+
```
|
|
576
|
+
Set (create array of IDs)
|
|
577
|
+
→ Split In Batches (10 items per batch)
|
|
578
|
+
→ HTTP Request (processes all 10 in parallel)
|
|
579
|
+
→ Loop
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### 2. Caching
|
|
583
|
+
```
|
|
584
|
+
IF (check cache exists)
|
|
585
|
+
├─ [Cache Hit] → Use cached data
|
|
586
|
+
└─ [Cache Miss] → HTTP Request → Store in cache
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### 3. Conditional Fetching
|
|
590
|
+
Only fetch if data changed:
|
|
591
|
+
```
|
|
592
|
+
HTTP Request (GET with If-Modified-Since header)
|
|
593
|
+
→ IF (status === 304)
|
|
594
|
+
└─ Use existing data
|
|
595
|
+
→ IF (status === 200)
|
|
596
|
+
└─ Process new data
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 4. Batch API Calls
|
|
600
|
+
If API supports batch operations:
|
|
601
|
+
```javascript
|
|
602
|
+
{
|
|
603
|
+
method: "POST",
|
|
604
|
+
url: "https://api.example.com/batch",
|
|
605
|
+
bodyParametersJson: JSON.stringify({
|
|
606
|
+
requests: $json.items.map(item => ({
|
|
607
|
+
method: "GET",
|
|
608
|
+
url: `/users/${item.id}`
|
|
609
|
+
}))
|
|
610
|
+
})
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## Common Gotchas
|
|
617
|
+
|
|
618
|
+
### 1. ❌ Wrong: Hardcoded URLs
|
|
619
|
+
```javascript
|
|
620
|
+
url: "https://api.example.com/prod/users"
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### ✅ Correct: Use environment variables
|
|
624
|
+
```javascript
|
|
625
|
+
url: "={{$env.API_BASE_URL}}/users"
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### 2. ❌ Wrong: Credentials in parameters
|
|
629
|
+
```javascript
|
|
630
|
+
headerParameters: {
|
|
631
|
+
"Authorization": "Bearer sk-abc123xyz" // ❌ Exposed!
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### ✅ Correct: Use credentials system
|
|
636
|
+
```javascript
|
|
637
|
+
authentication: "predefinedCredentialType",
|
|
638
|
+
nodeCredentialType: "httpHeaderAuth"
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### 3. ❌ Wrong: No error handling
|
|
642
|
+
```javascript
|
|
643
|
+
HTTP Request → Process (fails if API down)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### ✅ Correct: Handle errors
|
|
647
|
+
```javascript
|
|
648
|
+
HTTP Request (continueOnFail: true) → IF (error) → Handle
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
### 4. ❌ Wrong: Blocking on large responses
|
|
652
|
+
Processing 10,000 items synchronously
|
|
653
|
+
|
|
654
|
+
### ✅ Correct: Use batching
|
|
655
|
+
```
|
|
656
|
+
Split In Batches (100 items) → Process → Loop
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Real Template Examples
|
|
662
|
+
|
|
663
|
+
From n8n template library (892 API integration templates):
|
|
664
|
+
|
|
665
|
+
**GitHub to Notion**:
|
|
666
|
+
```
|
|
667
|
+
Schedule → HTTP Request (GitHub API) → Transform → HTTP Request (Notion API)
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
**Weather to Slack**:
|
|
671
|
+
```
|
|
672
|
+
Schedule → HTTP Request (Weather API) → Set (format) → Slack
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**CRM Sync**:
|
|
676
|
+
```
|
|
677
|
+
Schedule → HTTP Request (CRM A) → Transform → HTTP Request (CRM B)
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Use `search_templates({query: "http api"})` to find more!
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## Checklist for API Integration
|
|
685
|
+
|
|
686
|
+
### Planning
|
|
687
|
+
- [ ] Test API with Postman/curl first
|
|
688
|
+
- [ ] Understand response structure
|
|
689
|
+
- [ ] Check rate limits
|
|
690
|
+
- [ ] Review authentication method
|
|
691
|
+
- [ ] Plan error handling
|
|
692
|
+
|
|
693
|
+
### Implementation
|
|
694
|
+
- [ ] Use credentials (never hardcode)
|
|
695
|
+
- [ ] Configure proper HTTP method
|
|
696
|
+
- [ ] Set correct headers (Content-Type, Accept)
|
|
697
|
+
- [ ] Handle pagination if needed
|
|
698
|
+
- [ ] Add query parameters properly
|
|
699
|
+
|
|
700
|
+
### Error Handling
|
|
701
|
+
- [ ] Set continueOnFail: true if needed
|
|
702
|
+
- [ ] Check response status codes
|
|
703
|
+
- [ ] Implement retry logic
|
|
704
|
+
- [ ] Add Error Trigger workflow
|
|
705
|
+
- [ ] Alert on failures
|
|
706
|
+
|
|
707
|
+
### Performance
|
|
708
|
+
- [ ] Use batching for large datasets
|
|
709
|
+
- [ ] Add rate limiting if needed
|
|
710
|
+
- [ ] Consider caching
|
|
711
|
+
- [ ] Test with production load
|
|
712
|
+
|
|
713
|
+
### Security
|
|
714
|
+
- [ ] Use HTTPS only
|
|
715
|
+
- [ ] Store secrets in credentials
|
|
716
|
+
- [ ] Validate API responses
|
|
717
|
+
- [ ] Use environment variables
|
|
718
|
+
|
|
719
|
+
---
|
|
720
|
+
|
|
721
|
+
## Summary
|
|
722
|
+
|
|
723
|
+
**Key Points**:
|
|
724
|
+
1. **Authentication** via credentials system (never hardcode)
|
|
725
|
+
2. **Error handling** is critical (continueOnFail + IF checks)
|
|
726
|
+
3. **Pagination** for large datasets
|
|
727
|
+
4. **Rate limiting** to respect API limits
|
|
728
|
+
5. **Transform responses** to match your needs
|
|
729
|
+
|
|
730
|
+
**Pattern**: Trigger → HTTP Request → Transform → Action → Error Handler
|
|
731
|
+
|
|
732
|
+
**Related**:
|
|
733
|
+
- [webhook_processing.md](webhook_processing.md) - Receiving HTTP requests
|
|
734
|
+
- [database_operations.md](database_operations.md) - Storing API data
|