mirror of
https://github.com/czlonkowski/n8n-skills.git
synced 2026-03-16 23:43:08 +00:00
feat: Complete Skill #5 - n8n Node Configuration (ALL 5 SKILLS COMPLETE!)
Implements operation-aware node configuration with progressive discovery. Completes the final skill in the 5-skill n8n meta-skill collection. Files created: - 4 evaluations testing dependencies, operations, conditional fields, tool selection - SKILL.md (692 lines) - Configuration workflow, progressive discovery, patterns - DEPENDENCIES.md (671 lines) - displayOptions mechanism, dependency patterns - OPERATION_PATTERNS.md (783 lines) - 20+ nodes with common configurations - README.md (380 lines) - Skill metadata with usage statistics Key features: - Operation-aware configuration (resource + operation = requirements) - Property dependencies (displayOptions show/hide rules) - Progressive discovery (essentials → dependencies → info) - Configuration workflow (identify → discover → configure → validate → iterate) - 4 common node patterns (resource/operation, HTTP, database, conditional) - Tool selection guide (get_node_essentials 91.7% success rate) - Dependency troubleshooting (field visibility, conditional requirements) - 20+ node configuration examples with gotchas Progressive discovery strategy: 1. get_node_essentials (91.7% success, 18s avg from search) 2. get_property_dependencies (when dependencies unclear) 3. get_node_info (only when necessary, full schema) Property dependency patterns: - Boolean toggle (sendBody → body) - Resource/operation cascade (different ops → different fields) - Type-specific config (string vs number conditions) - Method-specific fields (GET vs POST) Common node patterns covered: - HTTP Request (GET/POST/PUT/DELETE with auth, query, body) - Webhook (basic/auth/response, $json.body gotcha) - Slack (post/update/create channel) - Gmail (send/get with filters) - Postgres (query/insert/update with parameters) - Set (fixed values/mapping with types) - Code (per-item/all-items, no expressions!) - IF (string/number/boolean, unary vs binary) - Switch (rules with fallback) - OpenAI (chat completion with system prompt) - Schedule (daily/interval/cron with timezone) Key insights: - 91.7% configurations succeed with essentials only - Average 56 seconds between configuration edits (iterative) - 9,835 essentials calls vs fewer full schema calls - 18 seconds average from node search to essentials - Different operations = different requirements (always check!) Top 5 gotchas documented: 1. Webhook data under $json.body (not $json) 2. POST needs sendBody: true 3. Slack channel format (#name for public) 4. SQL parameterized queries (prevent injection) 5. Schedule timezone must be explicit (DST handling) displayOptions mechanism: - show: Field appears when conditions match - hide: Field disappears when conditions match - AND logic: All conditions must match - OR logic: Any value matches - Nested: Parent value controls child structure Total: ~2,526 lines across 8 files Based on analysis of 38,287 workflow updates and 9,835 essentials calls. 🎉 ALL 5 CORE SKILLS NOW COMPLETE! 🎉 Skills completed: 1. ✅ n8n Expression Syntax (1,275 lines) 2. ✅ n8n MCP Tools Expert (1,325 lines) 3. ✅ n8n Workflow Patterns (3,932 lines) 4. ✅ n8n Validation Expert (2,553 lines) 5. ✅ n8n Node Configuration (2,526 lines) Total: ~11,611 lines across 36 files + 22 evaluations All skills data-driven from 447,557 real MCP tool usage events. 🤖 Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"id": "node-config-001",
|
||||||
|
"skills": ["n8n-node-configuration"],
|
||||||
|
"query": "I'm configuring an HTTP Request node with method=POST. What other fields become required or visible when I set this?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Explains property dependencies (displayOptions)",
|
||||||
|
"Identifies that sendBody becomes visible for POST",
|
||||||
|
"Explains that body becomes required when sendBody=true",
|
||||||
|
"Suggests using get_property_dependencies to see all dependencies",
|
||||||
|
"Provides guidance on checking conditional requirements",
|
||||||
|
"May reference DEPENDENCIES.md for detailed dependency rules"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"id": "node-config-002",
|
||||||
|
"skills": ["n8n-node-configuration"],
|
||||||
|
"query": "How do I configure a Slack node to post a message? What fields are required for this specific operation?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Identifies need to set resource='message' and operation='post'",
|
||||||
|
"Explains operation-specific required fields (channel, text)",
|
||||||
|
"Suggests using get_node_essentials with operation context",
|
||||||
|
"Provides example configuration for this operation",
|
||||||
|
"May reference OPERATION_PATTERNS.md for Slack patterns",
|
||||||
|
"Explains that different operations have different requirements"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"id": "node-config-003",
|
||||||
|
"skills": ["n8n-node-configuration"],
|
||||||
|
"query": "My IF node configuration is valid with operation='equals', but when I change to operation='isEmpty', validation fails. Why?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Explains that isEmpty is a unary operator (single value)",
|
||||||
|
"Identifies that value2 is not needed for unary operators",
|
||||||
|
"Explains singleValue property dependency",
|
||||||
|
"Mentions auto-sanitization will fix operator structure",
|
||||||
|
"Suggests using get_property_dependencies to understand operator rules",
|
||||||
|
"May reference DEPENDENCIES.md for operator-specific dependencies"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"id": "node-config-004",
|
||||||
|
"skills": ["n8n-node-configuration"],
|
||||||
|
"query": "Should I use get_node_essentials or get_node_info when configuring a new node? What's the difference?",
|
||||||
|
"expected_behavior": [
|
||||||
|
"Recommends get_node_essentials for configuration (91.7% success rate)",
|
||||||
|
"Explains essentials provides required fields and options",
|
||||||
|
"Explains get_node_info provides full schema (use when essentials insufficient)",
|
||||||
|
"Suggests starting with essentials, escalate to info if needed",
|
||||||
|
"May provide telemetry insight (essentials used 9,835 times)",
|
||||||
|
"References progressive disclosure approach"
|
||||||
|
]
|
||||||
|
}
|
||||||
800
skills/n8n-node-configuration/DEPENDENCIES.md
Normal file
800
skills/n8n-node-configuration/DEPENDENCIES.md
Normal file
@@ -0,0 +1,800 @@
|
|||||||
|
# Property Dependencies Guide
|
||||||
|
|
||||||
|
Deep dive into n8n property dependencies and displayOptions mechanism.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Are Property Dependencies?
|
||||||
|
|
||||||
|
**Definition**: Rules that control when fields are visible or required based on other field values.
|
||||||
|
|
||||||
|
**Mechanism**: `displayOptions` in node schema
|
||||||
|
|
||||||
|
**Purpose**:
|
||||||
|
- Show relevant fields only
|
||||||
|
- Hide irrelevant fields
|
||||||
|
- Simplify configuration UX
|
||||||
|
- Prevent invalid configurations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## displayOptions Structure
|
||||||
|
|
||||||
|
### Basic Format
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "fieldName",
|
||||||
|
"type": "string",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"otherField": ["value1", "value2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Translation**: Show `fieldName` when `otherField` equals "value1" OR "value2"
|
||||||
|
|
||||||
|
### Show vs Hide
|
||||||
|
|
||||||
|
#### show (Most Common)
|
||||||
|
|
||||||
|
**Show field when condition matches**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendBody": [true]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Meaning**: Show `body` when `sendBody = true`
|
||||||
|
|
||||||
|
#### hide (Less Common)
|
||||||
|
|
||||||
|
**Hide field when condition matches**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "advanced",
|
||||||
|
"displayOptions": {
|
||||||
|
"hide": {
|
||||||
|
"simpleMode": [true]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Meaning**: Hide `advanced` when `simpleMode = true`
|
||||||
|
|
||||||
|
### Multiple Conditions (AND Logic)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendBody": [true],
|
||||||
|
"method": ["POST", "PUT", "PATCH"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Meaning**: Show `body` when:
|
||||||
|
- `sendBody = true` AND
|
||||||
|
- `method IN (POST, PUT, PATCH)`
|
||||||
|
|
||||||
|
**All conditions must match** (AND logic)
|
||||||
|
|
||||||
|
### Multiple Values (OR Logic)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "someField",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"method": ["POST", "PUT", "PATCH"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Meaning**: Show `someField` when:
|
||||||
|
- `method = POST` OR
|
||||||
|
- `method = PUT` OR
|
||||||
|
- `method = PATCH`
|
||||||
|
|
||||||
|
**Any value matches** (OR logic)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Dependency Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Boolean Toggle
|
||||||
|
|
||||||
|
**Use case**: Optional feature flag
|
||||||
|
|
||||||
|
**Example**: HTTP Request sendBody
|
||||||
|
```javascript
|
||||||
|
// Field: sendBody (boolean)
|
||||||
|
{
|
||||||
|
"name": "sendBody",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field: body (depends on sendBody)
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendBody": [true]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Flow**:
|
||||||
|
1. User sees sendBody checkbox
|
||||||
|
2. When checked → body field appears
|
||||||
|
3. When unchecked → body field hides
|
||||||
|
|
||||||
|
### Pattern 2: Resource/Operation Cascade
|
||||||
|
|
||||||
|
**Use case**: Different operations show different fields
|
||||||
|
|
||||||
|
**Example**: Slack message operations
|
||||||
|
```javascript
|
||||||
|
// Operation: post
|
||||||
|
{
|
||||||
|
"name": "channel",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"resource": ["message"],
|
||||||
|
"operation": ["post"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation: update
|
||||||
|
{
|
||||||
|
"name": "messageId",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"resource": ["message"],
|
||||||
|
"operation": ["update"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Flow**:
|
||||||
|
1. User selects resource="message"
|
||||||
|
2. User selects operation="post" → sees channel
|
||||||
|
3. User changes to operation="update" → channel hides, messageId shows
|
||||||
|
|
||||||
|
### Pattern 3: Type-Specific Configuration
|
||||||
|
|
||||||
|
**Use case**: Different types need different fields
|
||||||
|
|
||||||
|
**Example**: IF node conditions
|
||||||
|
```javascript
|
||||||
|
// String operations
|
||||||
|
{
|
||||||
|
"name": "value2",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"conditions.string.0.operation": ["equals", "notEquals", "contains"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unary operations (isEmpty) don't show value2
|
||||||
|
{
|
||||||
|
"displayOptions": {
|
||||||
|
"hide": {
|
||||||
|
"conditions.string.0.operation": ["isEmpty", "isNotEmpty"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 4: Method-Specific Fields
|
||||||
|
|
||||||
|
**Use case**: HTTP methods have different options
|
||||||
|
|
||||||
|
**Example**: HTTP Request
|
||||||
|
```javascript
|
||||||
|
// Query parameters (all methods can have)
|
||||||
|
{
|
||||||
|
"name": "queryParameters",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendQuery": [true]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Body (only certain methods)
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendBody": [true],
|
||||||
|
"method": ["POST", "PUT", "PATCH", "DELETE"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Using get_property_dependencies
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const deps = get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Response
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"nodeType": "n8n-nodes-base.httpRequest",
|
||||||
|
"dependencies": {
|
||||||
|
"body": {
|
||||||
|
"shows_when": {
|
||||||
|
"sendBody": [true],
|
||||||
|
"method": ["POST", "PUT", "PATCH", "DELETE"]
|
||||||
|
},
|
||||||
|
"required_when_shown": true
|
||||||
|
},
|
||||||
|
"queryParameters": {
|
||||||
|
"shows_when": {
|
||||||
|
"sendQuery": [true]
|
||||||
|
},
|
||||||
|
"required_when_shown": false
|
||||||
|
},
|
||||||
|
"headerParameters": {
|
||||||
|
"shows_when": {
|
||||||
|
"sendHeaders": [true]
|
||||||
|
},
|
||||||
|
"required_when_shown": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### When to Use
|
||||||
|
|
||||||
|
**✅ Use when**:
|
||||||
|
- Validation fails with "missing field" but you don't see that field
|
||||||
|
- A field appears/disappears unexpectedly
|
||||||
|
- You need to understand what controls field visibility
|
||||||
|
- Building dynamic configuration tools
|
||||||
|
|
||||||
|
**❌ Don't use when**:
|
||||||
|
- Simple configuration (use get_node_essentials)
|
||||||
|
- Just starting configuration
|
||||||
|
- Field requirements are obvious
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Complex Dependency Examples
|
||||||
|
|
||||||
|
### Example 1: HTTP Request Complete Flow
|
||||||
|
|
||||||
|
**Scenario**: Configuring POST with JSON body
|
||||||
|
|
||||||
|
**Step 1**: Set method
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST"
|
||||||
|
// → sendBody becomes visible
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2**: Enable body
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"sendBody": true
|
||||||
|
// → body field becomes visible AND required
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3**: Configure body
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json"
|
||||||
|
// → content field becomes visible AND required
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4**: Add content
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "John",
|
||||||
|
"email": "john@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ✅ Valid!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependency chain**:
|
||||||
|
```
|
||||||
|
method=POST
|
||||||
|
→ sendBody visible
|
||||||
|
→ sendBody=true
|
||||||
|
→ body visible + required
|
||||||
|
→ body.contentType=json
|
||||||
|
→ body.content visible + required
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: IF Node Operator Dependencies
|
||||||
|
|
||||||
|
**Scenario**: String comparison with different operators
|
||||||
|
|
||||||
|
**Binary operator** (equals):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"operation": "equals"
|
||||||
|
// → value1 required
|
||||||
|
// → value2 required
|
||||||
|
// → singleValue should NOT be set
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Unary operator** (isEmpty):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"operation": "isEmpty"
|
||||||
|
// → value1 required
|
||||||
|
// → value2 should NOT be set
|
||||||
|
// → singleValue should be true (auto-added)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependency table**:
|
||||||
|
|
||||||
|
| Operator | value1 | value2 | singleValue |
|
||||||
|
|---|---|---|---|
|
||||||
|
| equals | Required | Required | false |
|
||||||
|
| notEquals | Required | Required | false |
|
||||||
|
| contains | Required | Required | false |
|
||||||
|
| isEmpty | Required | Hidden | true |
|
||||||
|
| isNotEmpty | Required | Hidden | true |
|
||||||
|
|
||||||
|
### Example 3: Slack Operation Matrix
|
||||||
|
|
||||||
|
**Scenario**: Different Slack operations show different fields
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// post message
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post"
|
||||||
|
// Shows: channel (required), text (required), attachments, blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update"
|
||||||
|
// Shows: messageId (required), text (required), channel (optional)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete message
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "delete"
|
||||||
|
// Shows: messageId (required), channel (required)
|
||||||
|
// Hides: text, attachments, blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
// get message
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "get"
|
||||||
|
// Shows: messageId (required), channel (required)
|
||||||
|
// Hides: text, attachments, blocks
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Field visibility matrix**:
|
||||||
|
|
||||||
|
| Field | post | update | delete | get |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| channel | Required | Optional | Required | Required |
|
||||||
|
| text | Required | Required | Hidden | Hidden |
|
||||||
|
| messageId | Hidden | Required | Required | Required |
|
||||||
|
| attachments | Optional | Optional | Hidden | Hidden |
|
||||||
|
| blocks | Optional | Optional | Hidden | Hidden |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nested Dependencies
|
||||||
|
|
||||||
|
### What Are They?
|
||||||
|
|
||||||
|
**Definition**: Dependencies within object properties
|
||||||
|
|
||||||
|
**Example**: HTTP Request body.contentType controls body.content structure
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
// → content expects JSON object
|
||||||
|
"content": {
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"contentType": "form-data",
|
||||||
|
// → content expects form fields array
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"name": "field1",
|
||||||
|
"value": "value1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### How to Handle
|
||||||
|
|
||||||
|
**Strategy**: Configure parent first, then children
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Step 1: Parent
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"contentType": "json" // Set parent first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Children (structure determined by parent)
|
||||||
|
{
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": { // JSON object format
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auto-Sanitization and Dependencies
|
||||||
|
|
||||||
|
### What Auto-Sanitization Fixes
|
||||||
|
|
||||||
|
**Operator structure issues** (IF/Switch nodes):
|
||||||
|
|
||||||
|
**Example**: singleValue property
|
||||||
|
```javascript
|
||||||
|
// You configure (missing singleValue)
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"operation": "isEmpty"
|
||||||
|
// Missing singleValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-sanitization adds it
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"operation": "isEmpty",
|
||||||
|
"singleValue": true // ✅ Added automatically
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### What It Doesn't Fix
|
||||||
|
|
||||||
|
**Missing required fields**:
|
||||||
|
```javascript
|
||||||
|
// You configure (missing channel)
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"text": "Hello"
|
||||||
|
// Missing required field: channel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-sanitization does NOT add
|
||||||
|
// You must add it yourself
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general", // ← You must add
|
||||||
|
"text": "Hello"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting Dependencies
|
||||||
|
|
||||||
|
### Problem 1: "Field X is required but not visible"
|
||||||
|
|
||||||
|
**Error**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "missing_required",
|
||||||
|
"property": "body",
|
||||||
|
"message": "body is required"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**But you don't see body field in configuration!**
|
||||||
|
|
||||||
|
**Solution**:
|
||||||
|
```javascript
|
||||||
|
// Check dependencies
|
||||||
|
const deps = get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find that body shows when sendBody=true
|
||||||
|
// Add sendBody
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"sendBody": true, // ← Now body appears!
|
||||||
|
"body": {...}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem 2: "Field disappears when I change operation"
|
||||||
|
|
||||||
|
**Scenario**:
|
||||||
|
```javascript
|
||||||
|
// Working configuration
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general",
|
||||||
|
"text": "Hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change operation
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update", // Changed
|
||||||
|
"channel": "#general", // Still here
|
||||||
|
"text": "Updated" // Still here
|
||||||
|
// Missing: messageId (required for update!)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Validation error**: "messageId is required"
|
||||||
|
|
||||||
|
**Why**: Different operation = different required fields
|
||||||
|
|
||||||
|
**Solution**:
|
||||||
|
```javascript
|
||||||
|
// Check essentials for new operation
|
||||||
|
get_node_essentials({
|
||||||
|
nodeType: "nodes-base.slack"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure for update operation
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update",
|
||||||
|
"messageId": "1234567890", // Required for update
|
||||||
|
"text": "Updated",
|
||||||
|
"channel": "#general" // Optional for update
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem 3: "Validation passes but field doesn't save"
|
||||||
|
|
||||||
|
**Scenario**: Field hidden by dependencies after validation
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```javascript
|
||||||
|
// Configure
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"sendBody": true, // ❌ GET doesn't support body
|
||||||
|
"body": {...} // This will be stripped
|
||||||
|
}
|
||||||
|
|
||||||
|
// After save
|
||||||
|
{
|
||||||
|
"method": "GET"
|
||||||
|
// body removed because method=GET hides it
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution**: Respect dependencies from the start
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Correct approach
|
||||||
|
get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
|
||||||
|
// See that body only shows for POST/PUT/PATCH/DELETE
|
||||||
|
// Use correct method
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {...}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Advanced Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Conditional Required with Fallback
|
||||||
|
|
||||||
|
**Example**: Channel can be string OR expression
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Option 1: String
|
||||||
|
{
|
||||||
|
"channel": "#general"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 2: Expression
|
||||||
|
{
|
||||||
|
"channel": "={{$json.channelName}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation accepts both
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 2: Mutually Exclusive Fields
|
||||||
|
|
||||||
|
**Example**: Use either ID or name, not both
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Use messageId
|
||||||
|
{
|
||||||
|
"messageId": "1234567890"
|
||||||
|
// name not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// OR use messageName
|
||||||
|
{
|
||||||
|
"messageName": "thread-name"
|
||||||
|
// messageId not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dependencies ensure only one is required
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Progressive Complexity
|
||||||
|
|
||||||
|
**Example**: Simple mode vs advanced mode
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Simple mode
|
||||||
|
{
|
||||||
|
"mode": "simple",
|
||||||
|
"text": "{{$json.message}}"
|
||||||
|
// Advanced fields hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advanced mode
|
||||||
|
{
|
||||||
|
"mode": "advanced",
|
||||||
|
"attachments": [...],
|
||||||
|
"blocks": [...],
|
||||||
|
"metadata": {...}
|
||||||
|
// Simple field hidden, advanced fields shown
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### ✅ Do
|
||||||
|
|
||||||
|
1. **Check dependencies when stuck**
|
||||||
|
```javascript
|
||||||
|
get_property_dependencies({nodeType: "..."});
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Configure parent properties first**
|
||||||
|
```javascript
|
||||||
|
// First: method, resource, operation
|
||||||
|
// Then: dependent fields
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Validate after changing operation**
|
||||||
|
```javascript
|
||||||
|
// Operation changed → requirements changed
|
||||||
|
validate_node_operation({...});
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Read validation errors for dependency hints**
|
||||||
|
```
|
||||||
|
Error: "body required when sendBody=true"
|
||||||
|
→ Hint: Set sendBody=true to enable body
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Don't
|
||||||
|
|
||||||
|
1. **Don't ignore dependency errors**
|
||||||
|
```javascript
|
||||||
|
// Error: "body not visible" → Check displayOptions
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Don't hardcode all possible fields**
|
||||||
|
```javascript
|
||||||
|
// Bad: Adding fields that will be hidden
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Don't assume operations are identical**
|
||||||
|
```javascript
|
||||||
|
// Each operation has unique requirements
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Key Concepts**:
|
||||||
|
- `displayOptions` control field visibility
|
||||||
|
- `show` = field appears when conditions match
|
||||||
|
- `hide` = field disappears when conditions match
|
||||||
|
- Multiple conditions = AND logic
|
||||||
|
- Multiple values = OR logic
|
||||||
|
|
||||||
|
**Common Patterns**:
|
||||||
|
1. Boolean toggle (sendBody → body)
|
||||||
|
2. Resource/operation cascade (different operations → different fields)
|
||||||
|
3. Type-specific config (string vs boolean conditions)
|
||||||
|
4. Method-specific fields (GET vs POST)
|
||||||
|
|
||||||
|
**Troubleshooting**:
|
||||||
|
- Field required but not visible → Check dependencies
|
||||||
|
- Field disappears after change → Operation changed requirements
|
||||||
|
- Field doesn't save → Hidden by dependencies
|
||||||
|
|
||||||
|
**Tools**:
|
||||||
|
- `get_property_dependencies` - See dependency rules
|
||||||
|
- `get_node_essentials` - See operation requirements
|
||||||
|
- Validation errors - Hints about dependencies
|
||||||
|
|
||||||
|
**Related Files**:
|
||||||
|
- **[SKILL.md](SKILL.md)** - Main configuration guide
|
||||||
|
- **[OPERATION_PATTERNS.md](OPERATION_PATTERNS.md)** - Common patterns by node type
|
||||||
913
skills/n8n-node-configuration/OPERATION_PATTERNS.md
Normal file
913
skills/n8n-node-configuration/OPERATION_PATTERNS.md
Normal file
@@ -0,0 +1,913 @@
|
|||||||
|
# Operation Patterns Guide
|
||||||
|
|
||||||
|
Common node configuration patterns organized by node type and operation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
**Purpose**: Quick reference for common node configurations
|
||||||
|
|
||||||
|
**Coverage**: Top 20 most-used nodes from 525 available
|
||||||
|
|
||||||
|
**Pattern format**:
|
||||||
|
- Minimal valid configuration
|
||||||
|
- Common options
|
||||||
|
- Real-world examples
|
||||||
|
- Gotchas and tips
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HTTP & API Nodes
|
||||||
|
|
||||||
|
### HTTP Request (nodes-base.httpRequest)
|
||||||
|
|
||||||
|
Most versatile node - 892 templates use this!
|
||||||
|
|
||||||
|
#### GET Request
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With query parameters**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendQuery": true,
|
||||||
|
"queryParameters": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"value": "100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "offset",
|
||||||
|
"value": "={{$json.offset}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With authentication**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "predefinedCredentialType",
|
||||||
|
"nodeCredentialType": "httpHeaderAuth"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### POST with JSON
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With expressions**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "={{$json.name}}",
|
||||||
|
"email": "={{$json.email}}",
|
||||||
|
"metadata": {
|
||||||
|
"source": "n8n",
|
||||||
|
"timestamp": "={{$now.toISO()}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Remember `sendBody: true` for POST/PUT/PATCH!
|
||||||
|
|
||||||
|
#### PUT/PATCH Request
|
||||||
|
|
||||||
|
**Pattern**: Same as POST, but method changes
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "PUT", // or "PATCH"
|
||||||
|
"url": "https://api.example.com/users/123",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "Updated Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### DELETE Request
|
||||||
|
|
||||||
|
**Minimal** (no body):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"url": "https://api.example.com/users/123",
|
||||||
|
"authentication": "none"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With body** (some APIs allow):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"ids": ["123", "456"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Webhook (nodes-base.webhook)
|
||||||
|
|
||||||
|
Most common trigger - 813 searches!
|
||||||
|
|
||||||
|
#### Basic Webhook
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"path": "my-webhook",
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"responseMode": "onReceived"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Webhook data is under `$json.body`, not `$json`!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ Wrong
|
||||||
|
{
|
||||||
|
"text": "={{$json.email}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Correct
|
||||||
|
{
|
||||||
|
"text": "={{$json.body.email}}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Webhook with Authentication
|
||||||
|
|
||||||
|
**Header auth**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"path": "secure-webhook",
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"responseMode": "onReceived",
|
||||||
|
"authentication": "headerAuth",
|
||||||
|
"options": {
|
||||||
|
"responseCode": 200,
|
||||||
|
"responseData": "{\n \"success\": true\n}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Webhook Returning Data
|
||||||
|
|
||||||
|
**Custom response**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"path": "my-webhook",
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"responseMode": "lastNode", // Return data from last node
|
||||||
|
"options": {
|
||||||
|
"responseCode": 201,
|
||||||
|
"responseHeaders": {
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"name": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Communication Nodes
|
||||||
|
|
||||||
|
### Slack (nodes-base.slack)
|
||||||
|
|
||||||
|
Second most popular - 234 AI agent templates use this!
|
||||||
|
|
||||||
|
#### Post Message
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general",
|
||||||
|
"text": "Hello from n8n!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With dynamic content**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "={{$json.channel}}",
|
||||||
|
"text": "New user: {{$json.name}} ({{$json.email}})"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With attachments**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#alerts",
|
||||||
|
"text": "Error Alert",
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"color": "#ff0000",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"title": "Error Type",
|
||||||
|
"value": "={{$json.errorType}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Timestamp",
|
||||||
|
"value": "={{$now.toLocaleString()}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Channel must start with `#` for public channels or be a channel ID!
|
||||||
|
|
||||||
|
#### Update Message
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update",
|
||||||
|
"messageId": "1234567890.123456", // From previous message post
|
||||||
|
"text": "Updated message content"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: `messageId` required, `channel` optional (can be inferred)
|
||||||
|
|
||||||
|
#### Create Channel
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "channel",
|
||||||
|
"operation": "create",
|
||||||
|
"name": "new-project-channel", // Lowercase, no spaces
|
||||||
|
"isPrivate": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Channel name must be lowercase, no spaces, 1-80 chars!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Gmail (nodes-base.gmail)
|
||||||
|
|
||||||
|
Popular for email automation
|
||||||
|
|
||||||
|
#### Send Email
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "send",
|
||||||
|
"to": "user@example.com",
|
||||||
|
"subject": "Hello from n8n",
|
||||||
|
"message": "This is the email body"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With dynamic content**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "send",
|
||||||
|
"to": "={{$json.email}}",
|
||||||
|
"subject": "Order Confirmation #{{$json.orderId}}",
|
||||||
|
"message": "Dear {{$json.name}},\n\nYour order has been confirmed.\n\nThank you!",
|
||||||
|
"options": {
|
||||||
|
"ccList": "admin@example.com",
|
||||||
|
"replyTo": "support@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Get Email
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "getAll",
|
||||||
|
"returnAll": false,
|
||||||
|
"limit": 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With filters**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "getAll",
|
||||||
|
"returnAll": false,
|
||||||
|
"limit": 50,
|
||||||
|
"filters": {
|
||||||
|
"q": "is:unread from:important@example.com",
|
||||||
|
"labelIds": ["INBOX"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database Nodes
|
||||||
|
|
||||||
|
### Postgres (nodes-base.postgres)
|
||||||
|
|
||||||
|
Database operations - 456 templates
|
||||||
|
|
||||||
|
#### Execute Query
|
||||||
|
|
||||||
|
**Minimal** (SELECT):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "executeQuery",
|
||||||
|
"query": "SELECT * FROM users WHERE active = true LIMIT 100"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With parameters** (SQL injection prevention):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "executeQuery",
|
||||||
|
"query": "SELECT * FROM users WHERE email = $1 AND active = $2",
|
||||||
|
"additionalFields": {
|
||||||
|
"mode": "list",
|
||||||
|
"queryParameters": "user@example.com,true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: ALWAYS use parameterized queries for user input!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ BAD - SQL injection risk!
|
||||||
|
{
|
||||||
|
"query": "SELECT * FROM users WHERE email = '{{$json.email}}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ GOOD - Parameterized
|
||||||
|
{
|
||||||
|
"query": "SELECT * FROM users WHERE email = $1",
|
||||||
|
"additionalFields": {
|
||||||
|
"mode": "list",
|
||||||
|
"queryParameters": "={{$json.email}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Insert
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "insert",
|
||||||
|
"table": "users",
|
||||||
|
"columns": "name,email,created_at",
|
||||||
|
"additionalFields": {
|
||||||
|
"mode": "list",
|
||||||
|
"queryParameters": "John Doe,john@example.com,NOW()"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With expressions**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "insert",
|
||||||
|
"table": "users",
|
||||||
|
"columns": "name,email,metadata",
|
||||||
|
"additionalFields": {
|
||||||
|
"mode": "list",
|
||||||
|
"queryParameters": "={{$json.name}},={{$json.email}},{{JSON.stringify($json)}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Update
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "update",
|
||||||
|
"table": "users",
|
||||||
|
"updateKey": "id",
|
||||||
|
"columns": "name,email",
|
||||||
|
"additionalFields": {
|
||||||
|
"mode": "list",
|
||||||
|
"queryParameters": "={{$json.id}},Updated Name,newemail@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Transformation Nodes
|
||||||
|
|
||||||
|
### Set (nodes-base.set)
|
||||||
|
|
||||||
|
Most used transformation - 68% of workflows!
|
||||||
|
|
||||||
|
#### Set Fixed Values
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "manual",
|
||||||
|
"duplicateItem": false,
|
||||||
|
"assignments": {
|
||||||
|
"assignments": [
|
||||||
|
{
|
||||||
|
"name": "status",
|
||||||
|
"value": "active",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "count",
|
||||||
|
"value": 100,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set from Input Data
|
||||||
|
|
||||||
|
**Mapping data**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "manual",
|
||||||
|
"duplicateItem": false,
|
||||||
|
"assignments": {
|
||||||
|
"assignments": [
|
||||||
|
{
|
||||||
|
"name": "fullName",
|
||||||
|
"value": "={{$json.firstName}} {{$json.lastName}}",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "email",
|
||||||
|
"value": "={{$json.email.toLowerCase()}}",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "timestamp",
|
||||||
|
"value": "={{$now.toISO()}}",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Use correct `type` for each field!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ Wrong type
|
||||||
|
{
|
||||||
|
"name": "age",
|
||||||
|
"value": "25", // String
|
||||||
|
"type": "string" // Will be string "25"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Correct type
|
||||||
|
{
|
||||||
|
"name": "age",
|
||||||
|
"value": 25, // Number
|
||||||
|
"type": "number" // Will be number 25
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Code (nodes-base.code)
|
||||||
|
|
||||||
|
JavaScript execution - 42% of workflows
|
||||||
|
|
||||||
|
#### Simple Transformation
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "runOnceForAllItems",
|
||||||
|
"jsCode": "return $input.all().map(item => ({\n json: {\n name: item.json.name.toUpperCase(),\n email: item.json.email\n }\n}));"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Per-item processing**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "runOnceForEachItem",
|
||||||
|
"jsCode": "// Process each item\nconst data = $input.item.json;\n\nreturn {\n json: {\n fullName: `${data.firstName} ${data.lastName}`,\n email: data.email.toLowerCase(),\n timestamp: new Date().toISOString()\n }\n};"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: In Code nodes, use `$input.item.json` or `$input.all()`, NOT `{{...}}`!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ Wrong - expressions don't work in Code nodes
|
||||||
|
{
|
||||||
|
"jsCode": "const name = '={{$json.name}}';"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Correct - direct access
|
||||||
|
{
|
||||||
|
"jsCode": "const name = $input.item.json.name;"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conditional Nodes
|
||||||
|
|
||||||
|
### IF (nodes-base.if)
|
||||||
|
|
||||||
|
Conditional logic - 38% of workflows
|
||||||
|
|
||||||
|
#### String Comparison
|
||||||
|
|
||||||
|
**Equals** (binary):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "active"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Contains** (binary):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.email}}",
|
||||||
|
"operation": "contains",
|
||||||
|
"value2": "@example.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**isEmpty** (unary):
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.email}}",
|
||||||
|
"operation": "isEmpty"
|
||||||
|
// No value2 - unary operator
|
||||||
|
// singleValue: true added by auto-sanitization
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Unary operators (isEmpty, isNotEmpty) don't need value2!
|
||||||
|
|
||||||
|
#### Number Comparison
|
||||||
|
|
||||||
|
**Greater than**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"number": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.age}}",
|
||||||
|
"operation": "larger",
|
||||||
|
"value2": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Boolean Comparison
|
||||||
|
|
||||||
|
**Is true**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"boolean": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.isActive}}",
|
||||||
|
"operation": "true"
|
||||||
|
// Unary - no value2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multiple Conditions (AND)
|
||||||
|
|
||||||
|
**All must match**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "active"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"number": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.age}}",
|
||||||
|
"operation": "larger",
|
||||||
|
"value2": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineOperation": "all" // AND logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multiple Conditions (OR)
|
||||||
|
|
||||||
|
**Any can match**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "pending"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"combineOperation": "any" // OR logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Switch (nodes-base.switch)
|
||||||
|
|
||||||
|
Multi-way routing - 18% of workflows
|
||||||
|
|
||||||
|
#### Basic Switch
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "rules",
|
||||||
|
"rules": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "active"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "pending"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"fallbackOutput": "extra" // Catch-all for non-matching
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Number of rules must match number of outputs!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Nodes
|
||||||
|
|
||||||
|
### OpenAI (nodes-langchain.openAi)
|
||||||
|
|
||||||
|
AI operations - 234 templates
|
||||||
|
|
||||||
|
#### Chat Completion
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "chat",
|
||||||
|
"operation": "complete",
|
||||||
|
"messages": {
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "={{$json.prompt}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**With system prompt**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "chat",
|
||||||
|
"operation": "complete",
|
||||||
|
"messages": {
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful assistant specialized in customer support."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "={{$json.userMessage}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"temperature": 0.7,
|
||||||
|
"maxTokens": 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Schedule Nodes
|
||||||
|
|
||||||
|
### Schedule Trigger (nodes-base.scheduleTrigger)
|
||||||
|
|
||||||
|
Time-based workflows - 28% have schedule triggers
|
||||||
|
|
||||||
|
#### Daily at Specific Time
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"rule": {
|
||||||
|
"interval": [
|
||||||
|
{
|
||||||
|
"field": "hours",
|
||||||
|
"hoursInterval": 24
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hour": 9,
|
||||||
|
"minute": 0,
|
||||||
|
"timezone": "America/New_York"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Gotcha**: Always set timezone explicitly!
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ Bad - uses server timezone
|
||||||
|
{
|
||||||
|
"rule": {
|
||||||
|
"interval": [...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Good - explicit timezone
|
||||||
|
{
|
||||||
|
"rule": {
|
||||||
|
"interval": [...],
|
||||||
|
"timezone": "America/New_York"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Every N Minutes
|
||||||
|
|
||||||
|
**Minimal**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"rule": {
|
||||||
|
"interval": [
|
||||||
|
{
|
||||||
|
"field": "minutes",
|
||||||
|
"minutesInterval": 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cron Expression
|
||||||
|
|
||||||
|
**Advanced scheduling**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"mode": "cron",
|
||||||
|
"cronExpression": "0 */2 * * *", // Every 2 hours
|
||||||
|
"timezone": "America/New_York"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Key Patterns by Category**:
|
||||||
|
|
||||||
|
| Category | Most Common | Key Gotcha |
|
||||||
|
|---|---|---|
|
||||||
|
| HTTP/API | GET, POST JSON | Remember sendBody: true |
|
||||||
|
| Webhooks | POST receiver | Data under $json.body |
|
||||||
|
| Communication | Slack post | Channel format (#name) |
|
||||||
|
| Database | SELECT with params | Use parameterized queries |
|
||||||
|
| Transform | Set assignments | Correct type per field |
|
||||||
|
| Conditional | IF string equals | Unary vs binary operators |
|
||||||
|
| AI | OpenAI chat | System + user messages |
|
||||||
|
| Schedule | Daily at time | Set timezone explicitly |
|
||||||
|
|
||||||
|
**Configuration Approach**:
|
||||||
|
1. Use patterns as starting point
|
||||||
|
2. Adapt to your use case
|
||||||
|
3. Validate configuration
|
||||||
|
4. Iterate based on errors
|
||||||
|
5. Deploy when valid
|
||||||
|
|
||||||
|
**Related Files**:
|
||||||
|
- **[SKILL.md](SKILL.md)** - Configuration workflow and philosophy
|
||||||
|
- **[DEPENDENCIES.md](DEPENDENCIES.md)** - Property dependency rules
|
||||||
366
skills/n8n-node-configuration/README.md
Normal file
366
skills/n8n-node-configuration/README.md
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
# n8n Node Configuration
|
||||||
|
|
||||||
|
Expert guidance for operation-aware node configuration with property dependencies.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
**Skill Name**: n8n Node Configuration
|
||||||
|
**Priority**: Medium
|
||||||
|
**Purpose**: Teach operation-aware configuration with progressive discovery and dependency awareness
|
||||||
|
|
||||||
|
## The Problem This Solves
|
||||||
|
|
||||||
|
From analysis of 447,557 MCP tool usage events:
|
||||||
|
|
||||||
|
- **38,287 workflow updates** (node configurations)
|
||||||
|
- **9,835 get_node_essentials calls** (18s avg from search → essentials)
|
||||||
|
- **91.7% success rate** with essentials-based configuration
|
||||||
|
- **56 seconds average** between configuration edits
|
||||||
|
|
||||||
|
**Key insight**: Most configurations only need essentials, not full schema!
|
||||||
|
|
||||||
|
## What This Skill Teaches
|
||||||
|
|
||||||
|
### Core Concepts
|
||||||
|
|
||||||
|
1. **Operation-Aware Configuration**
|
||||||
|
- Resource + operation determine required fields
|
||||||
|
- Different operations = different requirements
|
||||||
|
- Always check requirements when changing operation
|
||||||
|
|
||||||
|
2. **Property Dependencies**
|
||||||
|
- Fields appear/disappear based on other field values
|
||||||
|
- displayOptions control visibility
|
||||||
|
- Conditional required fields
|
||||||
|
- Understanding dependency chains
|
||||||
|
|
||||||
|
3. **Progressive Discovery**
|
||||||
|
- Start with get_node_essentials (91.7% success)
|
||||||
|
- Escalate to get_property_dependencies if needed
|
||||||
|
- Use get_node_info only when necessary
|
||||||
|
- Right tool for right job
|
||||||
|
|
||||||
|
4. **Configuration Workflow**
|
||||||
|
- Identify → Discover → Configure → Validate → Iterate
|
||||||
|
- Average 2-3 validation cycles
|
||||||
|
- Read errors for dependency hints
|
||||||
|
- 56 seconds between edits average
|
||||||
|
|
||||||
|
5. **Common Patterns**
|
||||||
|
- Resource/operation nodes (Slack, Sheets)
|
||||||
|
- HTTP-based nodes (HTTP Request, Webhook)
|
||||||
|
- Database nodes (Postgres, MySQL)
|
||||||
|
- Conditional logic nodes (IF, Switch)
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
n8n-node-configuration/
|
||||||
|
├── SKILL.md (692 lines)
|
||||||
|
│ Main configuration guide
|
||||||
|
│ - Configuration philosophy (progressive disclosure)
|
||||||
|
│ - Core concepts (operation-aware, dependencies)
|
||||||
|
│ - Configuration workflow (8-step process)
|
||||||
|
│ - get_node_essentials vs get_node_info
|
||||||
|
│ - Property dependencies deep dive
|
||||||
|
│ - Common node patterns (4 categories)
|
||||||
|
│ - Operation-specific examples
|
||||||
|
│ - Conditional requirements
|
||||||
|
│ - Anti-patterns and best practices
|
||||||
|
│
|
||||||
|
├── DEPENDENCIES.md (671 lines)
|
||||||
|
│ Property dependencies reference
|
||||||
|
│ - displayOptions mechanism
|
||||||
|
│ - show vs hide rules
|
||||||
|
│ - Multiple conditions (AND logic)
|
||||||
|
│ - Multiple values (OR logic)
|
||||||
|
│ - 4 common dependency patterns
|
||||||
|
│ - Using get_property_dependencies
|
||||||
|
│ - Complex dependency examples
|
||||||
|
│ - Nested dependencies
|
||||||
|
│ - Auto-sanitization interaction
|
||||||
|
│ - Troubleshooting guide
|
||||||
|
│ - Advanced patterns
|
||||||
|
│
|
||||||
|
├── OPERATION_PATTERNS.md (783 lines)
|
||||||
|
│ Common configurations by node type
|
||||||
|
│ - HTTP Request (GET/POST/PUT/DELETE)
|
||||||
|
│ - Webhook (basic/auth/response)
|
||||||
|
│ - Slack (post/update/create)
|
||||||
|
│ - Gmail (send/get)
|
||||||
|
│ - Postgres (query/insert/update)
|
||||||
|
│ - Set (values/mapping)
|
||||||
|
│ - Code (per-item/all-items)
|
||||||
|
│ - IF (string/number/boolean)
|
||||||
|
│ - Switch (rules/fallback)
|
||||||
|
│ - OpenAI (chat completion)
|
||||||
|
│ - Schedule (daily/interval/cron)
|
||||||
|
│ - Gotchas and tips for each
|
||||||
|
│
|
||||||
|
└── README.md (this file)
|
||||||
|
Skill metadata and statistics
|
||||||
|
```
|
||||||
|
|
||||||
|
**Total**: ~2,146 lines across 4 files + 4 evaluations
|
||||||
|
|
||||||
|
## Usage Statistics
|
||||||
|
|
||||||
|
From telemetry analysis:
|
||||||
|
|
||||||
|
| Metric | Value | Insight |
|
||||||
|
|---|---|---|
|
||||||
|
| Total workflow updates | 38,287 | High configuration activity |
|
||||||
|
| get_node_essentials calls | 9,835 | Most popular discovery pattern |
|
||||||
|
| Success rate (essentials) | 91.7% | Essentials sufficient for most |
|
||||||
|
| Avg time search→essentials | 18 seconds | Fast discovery workflow |
|
||||||
|
| Avg time between edits | 56 seconds | Iterative configuration |
|
||||||
|
|
||||||
|
## Tool Usage Pattern
|
||||||
|
|
||||||
|
**Most common discovery pattern** (9,835 occurrences):
|
||||||
|
```
|
||||||
|
search_nodes → get_node_essentials (18s avg)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Configuration cycle**:
|
||||||
|
```
|
||||||
|
get_node_essentials → configure → validate → iterate (56s avg per edit)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Insights
|
||||||
|
|
||||||
|
### 1. Progressive Disclosure Works
|
||||||
|
|
||||||
|
**91.7% success rate** with get_node_essentials proves most configurations don't need full schema.
|
||||||
|
|
||||||
|
**Strategy**:
|
||||||
|
1. Start with essentials
|
||||||
|
2. Escalate to dependencies if stuck
|
||||||
|
3. Use full schema only when necessary
|
||||||
|
|
||||||
|
### 2. Operations Determine Requirements
|
||||||
|
|
||||||
|
**Same node, different operation = different requirements**
|
||||||
|
|
||||||
|
Example: Slack message
|
||||||
|
- `operation="post"` → needs channel + text
|
||||||
|
- `operation="update"` → needs messageId + text (different!)
|
||||||
|
|
||||||
|
### 3. Dependencies Control Visibility
|
||||||
|
|
||||||
|
**Fields appear/disappear based on other values**
|
||||||
|
|
||||||
|
Example: HTTP Request
|
||||||
|
- `method="GET"` → body hidden
|
||||||
|
- `method="POST"` + `sendBody=true` → body required
|
||||||
|
|
||||||
|
### 4. Configuration is Iterative
|
||||||
|
|
||||||
|
**Average 56 seconds between edits** shows configuration is iterative, not one-shot.
|
||||||
|
|
||||||
|
**Normal workflow**:
|
||||||
|
1. Configure minimal
|
||||||
|
2. Validate → error
|
||||||
|
3. Add missing field
|
||||||
|
4. Validate → error
|
||||||
|
5. Adjust value
|
||||||
|
6. Validate → valid ✅
|
||||||
|
|
||||||
|
### 5. Common Gotchas Exist
|
||||||
|
|
||||||
|
**Top 5 gotchas** from patterns:
|
||||||
|
1. Webhook data under `$json.body` (not `$json`)
|
||||||
|
2. POST needs `sendBody: true`
|
||||||
|
3. Slack channel format (`#name`)
|
||||||
|
4. SQL parameterized queries (injection prevention)
|
||||||
|
5. Timezone must be explicit (schedule nodes)
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Example 1: Basic Configuration Flow
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Step 1: Get essentials
|
||||||
|
const info = get_node_essentials({
|
||||||
|
nodeType: "nodes-base.slack"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 2: Configure for operation
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general",
|
||||||
|
"text": "Hello!"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Validate
|
||||||
|
validate_node_operation({...});
|
||||||
|
// ✅ Valid!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Handling Dependencies
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Step 1: Configure HTTP POST
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/create"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Validate → Error: "sendBody required"
|
||||||
|
// Step 3: Check dependencies
|
||||||
|
get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
// Shows: body visible when sendBody=true
|
||||||
|
|
||||||
|
// Step 4: Fix
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/create",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {...}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ✅ Valid!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Operation Change
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Initial config (post operation)
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general",
|
||||||
|
"text": "Hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change operation
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update", // Changed!
|
||||||
|
// Need to check new requirements
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get essentials for update operation
|
||||||
|
get_node_essentials({nodeType: "nodes-base.slack"});
|
||||||
|
// Shows: messageId required, channel optional
|
||||||
|
|
||||||
|
// Correct config
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update",
|
||||||
|
"messageId": "1234567890.123456",
|
||||||
|
"text": "Updated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## When This Skill Activates
|
||||||
|
|
||||||
|
**Trigger phrases**:
|
||||||
|
- "how to configure"
|
||||||
|
- "what fields are required"
|
||||||
|
- "property dependencies"
|
||||||
|
- "get_node_essentials vs get_node_info"
|
||||||
|
- "operation-specific"
|
||||||
|
- "field not visible"
|
||||||
|
|
||||||
|
**Common scenarios**:
|
||||||
|
- Configuring new nodes
|
||||||
|
- Understanding required fields
|
||||||
|
- Field appears/disappears unexpectedly
|
||||||
|
- Choosing between discovery tools
|
||||||
|
- Switching operations
|
||||||
|
- Learning common patterns
|
||||||
|
|
||||||
|
## Integration with Other Skills
|
||||||
|
|
||||||
|
### Works With:
|
||||||
|
- **n8n MCP Tools Expert** - How to call discovery tools correctly
|
||||||
|
- **n8n Validation Expert** - Interpret missing_required errors
|
||||||
|
- **n8n Expression Syntax** - Configure expression fields
|
||||||
|
- **n8n Workflow Patterns** - Apply patterns with proper node config
|
||||||
|
|
||||||
|
### Complementary:
|
||||||
|
- Use MCP Tools Expert to learn tool selection
|
||||||
|
- Use Validation Expert to fix configuration errors
|
||||||
|
- Use Expression Syntax for dynamic field values
|
||||||
|
- Use Workflow Patterns to understand node relationships
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
**Evaluations**: 4 test scenarios
|
||||||
|
|
||||||
|
1. **eval-001-property-dependencies.json**
|
||||||
|
- Tests understanding of displayOptions
|
||||||
|
- Guides to get_property_dependencies
|
||||||
|
- Explains conditional requirements
|
||||||
|
|
||||||
|
2. **eval-002-operation-specific-config.json**
|
||||||
|
- Tests operation-aware configuration
|
||||||
|
- Identifies resource + operation pattern
|
||||||
|
- References OPERATION_PATTERNS.md
|
||||||
|
|
||||||
|
3. **eval-003-conditional-fields.json**
|
||||||
|
- Tests unary vs binary operators
|
||||||
|
- Explains singleValue dependency
|
||||||
|
- Mentions auto-sanitization
|
||||||
|
|
||||||
|
4. **eval-004-essentials-vs-info.json**
|
||||||
|
- Tests tool selection knowledge
|
||||||
|
- Explains progressive disclosure
|
||||||
|
- Provides success rate statistics
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
**Before this skill**:
|
||||||
|
- Using get_node_info for everything (slow, overwhelming)
|
||||||
|
- Not understanding property dependencies
|
||||||
|
- Confused when fields appear/disappear
|
||||||
|
- Not aware of operation-specific requirements
|
||||||
|
- Trial and error configuration
|
||||||
|
|
||||||
|
**After this skill**:
|
||||||
|
- Start with get_node_essentials (91.7% success)
|
||||||
|
- Understand displayOptions mechanism
|
||||||
|
- Predict field visibility based on dependencies
|
||||||
|
- Check requirements when changing operations
|
||||||
|
- Systematic configuration approach
|
||||||
|
- Know common patterns by node type
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
|
||||||
|
**Node types covered**: Top 20 most-used nodes
|
||||||
|
|
||||||
|
| Category | Nodes | Coverage |
|
||||||
|
|---|---|---|
|
||||||
|
| HTTP/API | HTTP Request, Webhook | Complete |
|
||||||
|
| Communication | Slack, Gmail | Common operations |
|
||||||
|
| Database | Postgres, MySQL | CRUD operations |
|
||||||
|
| Transform | Set, Code | All modes |
|
||||||
|
| Conditional | IF, Switch | All operator types |
|
||||||
|
| AI | OpenAI | Chat completion |
|
||||||
|
| Schedule | Schedule Trigger | All modes |
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- **n8n-mcp MCP Server**: Provides discovery tools
|
||||||
|
- **n8n Node API**: get_node_essentials, get_property_dependencies, get_node_info
|
||||||
|
- **n8n Schema**: displayOptions mechanism, property definitions
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
- **v1.0** (2025-10-20): Initial implementation
|
||||||
|
- SKILL.md with configuration workflow
|
||||||
|
- DEPENDENCIES.md with displayOptions deep dive
|
||||||
|
- OPERATION_PATTERNS.md with 20+ node patterns
|
||||||
|
- 4 evaluation scenarios
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en)
|
||||||
|
|
||||||
|
Part of the n8n-skills meta-skill collection.
|
||||||
775
skills/n8n-node-configuration/SKILL.md
Normal file
775
skills/n8n-node-configuration/SKILL.md
Normal file
@@ -0,0 +1,775 @@
|
|||||||
|
---
|
||||||
|
name: n8n Node Configuration
|
||||||
|
description: Operation-aware node configuration guidance. Use when configuring nodes, understanding property dependencies, determining required fields, choosing between get_node_essentials and get_node_info, or learning common configuration patterns by node type.
|
||||||
|
---
|
||||||
|
|
||||||
|
# n8n Node Configuration
|
||||||
|
|
||||||
|
Expert guidance for operation-aware node configuration with property dependencies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration Philosophy
|
||||||
|
|
||||||
|
**Progressive disclosure**: Start minimal, add complexity as needed
|
||||||
|
|
||||||
|
From telemetry analysis:
|
||||||
|
- 38,287 workflow updates (node configurations)
|
||||||
|
- 9,835 get_node_essentials calls (most used discovery pattern)
|
||||||
|
- 56 seconds average between configuration edits
|
||||||
|
- 91.7% success rate with essentials-based configuration
|
||||||
|
|
||||||
|
**Key insight**: Most configurations need only essentials, not full schema!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
### 1. Operation-Aware Configuration
|
||||||
|
|
||||||
|
**Not all fields are always required** - it depends on operation!
|
||||||
|
|
||||||
|
**Example**: Slack node
|
||||||
|
```javascript
|
||||||
|
// For operation='post'
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general", // Required for post
|
||||||
|
"text": "Hello!" // Required for post
|
||||||
|
}
|
||||||
|
|
||||||
|
// For operation='update'
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update",
|
||||||
|
"messageId": "123", // Required for update (different!)
|
||||||
|
"text": "Updated!" // Required for update
|
||||||
|
// channel NOT required for update
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key**: Resource + operation determine which fields are required!
|
||||||
|
|
||||||
|
### 2. Property Dependencies
|
||||||
|
|
||||||
|
**Fields appear/disappear based on other field values**
|
||||||
|
|
||||||
|
**Example**: HTTP Request node
|
||||||
|
```javascript
|
||||||
|
// When method='GET'
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.example.com"
|
||||||
|
// sendBody not shown (GET doesn't have body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When method='POST'
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com",
|
||||||
|
"sendBody": true, // Now visible!
|
||||||
|
"body": { // Required when sendBody=true
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {...}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Mechanism**: displayOptions control field visibility
|
||||||
|
|
||||||
|
### 3. Progressive Discovery
|
||||||
|
|
||||||
|
**Use the right tool for the right job**:
|
||||||
|
|
||||||
|
1. **get_node_essentials** (91.7% success rate)
|
||||||
|
- Quick overview
|
||||||
|
- Required fields
|
||||||
|
- Common options
|
||||||
|
- **Use first** - covers 90% of needs
|
||||||
|
|
||||||
|
2. **get_property_dependencies** (for complex nodes)
|
||||||
|
- Shows what fields depend on others
|
||||||
|
- Reveals conditional requirements
|
||||||
|
- Use when essentials isn't enough
|
||||||
|
|
||||||
|
3. **get_node_info** (full schema)
|
||||||
|
- Complete documentation
|
||||||
|
- All possible fields
|
||||||
|
- Use when essentials + dependencies insufficient
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration Workflow
|
||||||
|
|
||||||
|
### Standard Process
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Identify node type and operation
|
||||||
|
↓
|
||||||
|
2. Use get_node_essentials
|
||||||
|
↓
|
||||||
|
3. Configure required fields
|
||||||
|
↓
|
||||||
|
4. Validate configuration
|
||||||
|
↓
|
||||||
|
5. If dependencies unclear → get_property_dependencies
|
||||||
|
↓
|
||||||
|
6. Add optional fields as needed
|
||||||
|
↓
|
||||||
|
7. Validate again
|
||||||
|
↓
|
||||||
|
8. Deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Configuring HTTP Request
|
||||||
|
|
||||||
|
**Step 1**: Identify what you need
|
||||||
|
```javascript
|
||||||
|
// Goal: POST JSON to API
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2**: Get essentials
|
||||||
|
```javascript
|
||||||
|
const info = get_node_essentials({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Returns: method, url, sendBody, body, authentication required/optional
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3**: Minimal config
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/create",
|
||||||
|
"authentication": "none"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 4**: Validate
|
||||||
|
```javascript
|
||||||
|
validate_node_operation({
|
||||||
|
nodeType: "nodes-base.httpRequest",
|
||||||
|
config,
|
||||||
|
profile: "runtime"
|
||||||
|
});
|
||||||
|
// → Error: "sendBody required for POST"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5**: Add required field
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/create",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 6**: Validate again
|
||||||
|
```javascript
|
||||||
|
validate_node_operation({...});
|
||||||
|
// → Error: "body required when sendBody=true"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 7**: Complete configuration
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/create",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true,
|
||||||
|
"body": {
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "={{$json.name}}",
|
||||||
|
"email": "={{$json.email}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 8**: Final validation
|
||||||
|
```javascript
|
||||||
|
validate_node_operation({...});
|
||||||
|
// → Valid! ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## get_node_essentials vs get_node_info
|
||||||
|
|
||||||
|
### Use get_node_essentials When:
|
||||||
|
|
||||||
|
**✅ Starting configuration** (91.7% success rate)
|
||||||
|
```javascript
|
||||||
|
get_node_essentials({
|
||||||
|
nodeType: "nodes-base.slack"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
- Required fields
|
||||||
|
- Common options
|
||||||
|
- Basic examples
|
||||||
|
- Operation list
|
||||||
|
|
||||||
|
**Fast**: ~18 seconds average (from search → essentials)
|
||||||
|
|
||||||
|
### Use get_node_info When:
|
||||||
|
|
||||||
|
**✅ Essentials insufficient**
|
||||||
|
```javascript
|
||||||
|
get_node_info({
|
||||||
|
nodeType: "nodes-base.slack"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
- Full schema
|
||||||
|
- All properties
|
||||||
|
- Complete documentation
|
||||||
|
- Advanced options
|
||||||
|
|
||||||
|
**Slower**: More data to process
|
||||||
|
|
||||||
|
### Decision Tree
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ Starting new node config? │
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ YES → get_node_essentials │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ Essentials has what you need? │
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ YES → Configure with essentials │
|
||||||
|
│ NO → Continue │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ Need dependency info? │
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ YES → get_property_dependencies │
|
||||||
|
│ NO → Continue │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ Still need more details? │
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ YES → get_node_info │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Property Dependencies Deep Dive
|
||||||
|
|
||||||
|
### displayOptions Mechanism
|
||||||
|
|
||||||
|
**Fields have visibility rules**:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"displayOptions": {
|
||||||
|
"show": {
|
||||||
|
"sendBody": [true],
|
||||||
|
"method": ["POST", "PUT", "PATCH"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Translation**: "body" field shows when:
|
||||||
|
- sendBody = true AND
|
||||||
|
- method = POST, PUT, or PATCH
|
||||||
|
|
||||||
|
### Common Dependency Patterns
|
||||||
|
|
||||||
|
#### Pattern 1: Boolean Toggle
|
||||||
|
|
||||||
|
**Example**: HTTP Request sendBody
|
||||||
|
```javascript
|
||||||
|
// sendBody controls body visibility
|
||||||
|
{
|
||||||
|
"sendBody": true // → body field appears
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pattern 2: Operation Switch
|
||||||
|
|
||||||
|
**Example**: Slack resource/operation
|
||||||
|
```javascript
|
||||||
|
// Different operations → different fields
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post"
|
||||||
|
// → Shows: channel, text, attachments, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update"
|
||||||
|
// → Shows: messageId, text (different fields!)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pattern 3: Type Selection
|
||||||
|
|
||||||
|
**Example**: IF node conditions
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"operation": "contains"
|
||||||
|
// → Shows: value1, value2
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"operation": "equals"
|
||||||
|
// → Shows: value1, value2, different operators
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using get_property_dependencies
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```javascript
|
||||||
|
const deps = get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Returns dependency tree
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"body": {
|
||||||
|
"shows_when": {
|
||||||
|
"sendBody": [true],
|
||||||
|
"method": ["POST", "PUT", "PATCH", "DELETE"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryParameters": {
|
||||||
|
"shows_when": {
|
||||||
|
"sendQuery": [true]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use this when**: Validation fails and you don't understand why field is missing/required
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Node Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Resource/Operation Nodes
|
||||||
|
|
||||||
|
**Examples**: Slack, Google Sheets, Airtable
|
||||||
|
|
||||||
|
**Structure**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "<entity>", // What type of thing
|
||||||
|
"operation": "<action>", // What to do with it
|
||||||
|
// ... operation-specific fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**How to configure**:
|
||||||
|
1. Choose resource
|
||||||
|
2. Choose operation
|
||||||
|
3. Use get_node_essentials to see operation-specific requirements
|
||||||
|
4. Configure required fields
|
||||||
|
|
||||||
|
### Pattern 2: HTTP-Based Nodes
|
||||||
|
|
||||||
|
**Examples**: HTTP Request, Webhook
|
||||||
|
|
||||||
|
**Structure**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "<HTTP_METHOD>",
|
||||||
|
"url": "<endpoint>",
|
||||||
|
"authentication": "<type>",
|
||||||
|
// ... method-specific fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies**:
|
||||||
|
- POST/PUT/PATCH → sendBody available
|
||||||
|
- sendBody=true → body required
|
||||||
|
- authentication != "none" → credentials required
|
||||||
|
|
||||||
|
### Pattern 3: Database Nodes
|
||||||
|
|
||||||
|
**Examples**: Postgres, MySQL, MongoDB
|
||||||
|
|
||||||
|
**Structure**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"operation": "<query|insert|update|delete>",
|
||||||
|
// ... operation-specific fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies**:
|
||||||
|
- operation="executeQuery" → query required
|
||||||
|
- operation="insert" → table + values required
|
||||||
|
- operation="update" → table + values + where required
|
||||||
|
|
||||||
|
### Pattern 4: Conditional Logic Nodes
|
||||||
|
|
||||||
|
**Examples**: IF, Switch, Merge
|
||||||
|
|
||||||
|
**Structure**:
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"<type>": [
|
||||||
|
{
|
||||||
|
"operation": "<operator>",
|
||||||
|
"value1": "...",
|
||||||
|
"value2": "..." // Only for binary operators
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependencies**:
|
||||||
|
- Binary operators (equals, contains, etc.) → value1 + value2
|
||||||
|
- Unary operators (isEmpty, isNotEmpty) → value1 only + singleValue: true
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Operation-Specific Configuration
|
||||||
|
|
||||||
|
### Slack Node Examples
|
||||||
|
|
||||||
|
#### Post Message
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general", // Required
|
||||||
|
"text": "Hello!", // Required
|
||||||
|
"attachments": [], // Optional
|
||||||
|
"blocks": [] // Optional
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Update Message
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update",
|
||||||
|
"messageId": "1234567890", // Required (different from post!)
|
||||||
|
"text": "Updated!", // Required
|
||||||
|
"channel": "#general" // Optional (can be inferred)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Create Channel
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"resource": "channel",
|
||||||
|
"operation": "create",
|
||||||
|
"name": "new-channel", // Required
|
||||||
|
"isPrivate": false // Optional
|
||||||
|
// Note: text NOT required for this operation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Request Node Examples
|
||||||
|
|
||||||
|
#### GET Request
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "predefinedCredentialType",
|
||||||
|
"nodeCredentialType": "httpHeaderAuth",
|
||||||
|
"sendQuery": true, // Optional
|
||||||
|
"queryParameters": { // Shows when sendQuery=true
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "limit",
|
||||||
|
"value": "100"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### POST with JSON
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"url": "https://api.example.com/users",
|
||||||
|
"authentication": "none",
|
||||||
|
"sendBody": true, // Required for POST
|
||||||
|
"body": { // Required when sendBody=true
|
||||||
|
"contentType": "json",
|
||||||
|
"content": {
|
||||||
|
"name": "John Doe",
|
||||||
|
"email": "john@example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IF Node Examples
|
||||||
|
|
||||||
|
#### String Comparison (Binary)
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.status}}",
|
||||||
|
"operation": "equals",
|
||||||
|
"value2": "active" // Binary: needs value2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Empty Check (Unary)
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"conditions": {
|
||||||
|
"string": [
|
||||||
|
{
|
||||||
|
"value1": "={{$json.email}}",
|
||||||
|
"operation": "isEmpty",
|
||||||
|
// No value2 - unary operator
|
||||||
|
"singleValue": true // Auto-added by sanitization
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Handling Conditional Requirements
|
||||||
|
|
||||||
|
### Example: HTTP Request Body
|
||||||
|
|
||||||
|
**Scenario**: body field required, but only sometimes
|
||||||
|
|
||||||
|
**Rule**:
|
||||||
|
```
|
||||||
|
body is required when:
|
||||||
|
- sendBody = true AND
|
||||||
|
- method IN (POST, PUT, PATCH, DELETE)
|
||||||
|
```
|
||||||
|
|
||||||
|
**How to discover**:
|
||||||
|
```javascript
|
||||||
|
// Option 1: Read validation error
|
||||||
|
validate_node_operation({...});
|
||||||
|
// Error: "body required when sendBody=true"
|
||||||
|
|
||||||
|
// Option 2: Check dependencies
|
||||||
|
get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.httpRequest"
|
||||||
|
});
|
||||||
|
// Shows: body → shows_when: sendBody=[true], method=[POST,PUT,PATCH,DELETE]
|
||||||
|
|
||||||
|
// Option 3: Try minimal config and iterate
|
||||||
|
// Start without body, validation will tell you if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: IF Node singleValue
|
||||||
|
|
||||||
|
**Scenario**: singleValue property appears for unary operators
|
||||||
|
|
||||||
|
**Rule**:
|
||||||
|
```
|
||||||
|
singleValue should be true when:
|
||||||
|
- operation IN (isEmpty, isNotEmpty, true, false)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Good news**: Auto-sanitization fixes this!
|
||||||
|
|
||||||
|
**Manual check**:
|
||||||
|
```javascript
|
||||||
|
get_property_dependencies({
|
||||||
|
nodeType: "nodes-base.if"
|
||||||
|
});
|
||||||
|
// Shows operator-specific dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration Anti-Patterns
|
||||||
|
|
||||||
|
### ❌ Don't: Over-configure Upfront
|
||||||
|
|
||||||
|
**Bad**:
|
||||||
|
```javascript
|
||||||
|
// Adding every possible field
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "...",
|
||||||
|
"sendQuery": false,
|
||||||
|
"sendHeaders": false,
|
||||||
|
"sendBody": false,
|
||||||
|
"timeout": 10000,
|
||||||
|
"ignoreResponseCode": false,
|
||||||
|
// ... 20 more optional fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Good**:
|
||||||
|
```javascript
|
||||||
|
// Start minimal
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"url": "...",
|
||||||
|
"authentication": "none"
|
||||||
|
}
|
||||||
|
// Add fields only when needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Don't: Skip Validation
|
||||||
|
|
||||||
|
**Bad**:
|
||||||
|
```javascript
|
||||||
|
// Configure and deploy without validating
|
||||||
|
const config = {...};
|
||||||
|
n8n_update_partial_workflow({...}); // YOLO
|
||||||
|
```
|
||||||
|
|
||||||
|
**Good**:
|
||||||
|
```javascript
|
||||||
|
// Validate before deploying
|
||||||
|
const config = {...};
|
||||||
|
const result = validate_node_operation({...});
|
||||||
|
if (result.valid) {
|
||||||
|
n8n_update_partial_workflow({...});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Don't: Ignore Operation Context
|
||||||
|
|
||||||
|
**Bad**:
|
||||||
|
```javascript
|
||||||
|
// Same config for all Slack operations
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "post",
|
||||||
|
"channel": "#general",
|
||||||
|
"text": "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then switching operation without updating config
|
||||||
|
{
|
||||||
|
"resource": "message",
|
||||||
|
"operation": "update", // Changed
|
||||||
|
"channel": "#general", // Wrong field for update!
|
||||||
|
"text": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Good**:
|
||||||
|
```javascript
|
||||||
|
// Check requirements when changing operation
|
||||||
|
get_node_essentials({
|
||||||
|
nodeType: "nodes-base.slack"
|
||||||
|
});
|
||||||
|
// See what update operation needs (messageId, not channel)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### ✅ Do
|
||||||
|
|
||||||
|
1. **Start with get_node_essentials**
|
||||||
|
- 91.7% success rate
|
||||||
|
- Faster than get_node_info
|
||||||
|
- Sufficient for most needs
|
||||||
|
|
||||||
|
2. **Validate iteratively**
|
||||||
|
- Configure → Validate → Fix → Repeat
|
||||||
|
- Average 2-3 iterations is normal
|
||||||
|
- Read validation errors carefully
|
||||||
|
|
||||||
|
3. **Use property dependencies when stuck**
|
||||||
|
- If field seems missing, check dependencies
|
||||||
|
- Understand what controls field visibility
|
||||||
|
- get_property_dependencies reveals rules
|
||||||
|
|
||||||
|
4. **Respect operation context**
|
||||||
|
- Different operations = different requirements
|
||||||
|
- Always check essentials when changing operation
|
||||||
|
- Don't assume configs are transferable
|
||||||
|
|
||||||
|
5. **Trust auto-sanitization**
|
||||||
|
- Operator structure fixed automatically
|
||||||
|
- Don't manually add/remove singleValue
|
||||||
|
- IF/Switch metadata added on save
|
||||||
|
|
||||||
|
### ❌ Don't
|
||||||
|
|
||||||
|
1. **Jump to get_node_info immediately**
|
||||||
|
- Try essentials first
|
||||||
|
- Only escalate if needed
|
||||||
|
- Full schema is overwhelming
|
||||||
|
|
||||||
|
2. **Configure blindly**
|
||||||
|
- Always validate before deploying
|
||||||
|
- Understand why fields are required
|
||||||
|
- Check dependencies for conditional fields
|
||||||
|
|
||||||
|
3. **Copy configs without understanding**
|
||||||
|
- Different operations need different fields
|
||||||
|
- Validate after copying
|
||||||
|
- Adjust for new context
|
||||||
|
|
||||||
|
4. **Manually fix auto-sanitization issues**
|
||||||
|
- Let auto-sanitization handle operator structure
|
||||||
|
- Focus on business logic
|
||||||
|
- Save and let system fix structure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Detailed References
|
||||||
|
|
||||||
|
For comprehensive guides on specific topics:
|
||||||
|
|
||||||
|
- **[DEPENDENCIES.md](DEPENDENCIES.md)** - Deep dive into property dependencies and displayOptions
|
||||||
|
- **[OPERATION_PATTERNS.md](OPERATION_PATTERNS.md)** - Common configuration patterns by node type
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Configuration Strategy**:
|
||||||
|
1. Start with get_node_essentials (91.7% success)
|
||||||
|
2. Configure required fields for operation
|
||||||
|
3. Validate configuration
|
||||||
|
4. Check dependencies if stuck
|
||||||
|
5. Iterate until valid (avg 2-3 cycles)
|
||||||
|
6. Deploy with confidence
|
||||||
|
|
||||||
|
**Key Principles**:
|
||||||
|
- **Operation-aware**: Different operations = different requirements
|
||||||
|
- **Progressive disclosure**: Start minimal, add as needed
|
||||||
|
- **Dependency-aware**: Understand field visibility rules
|
||||||
|
- **Validation-driven**: Let validation guide configuration
|
||||||
|
|
||||||
|
**Related Skills**:
|
||||||
|
- **n8n MCP Tools Expert** - How to use discovery tools correctly
|
||||||
|
- **n8n Validation Expert** - Interpret validation errors
|
||||||
|
- **n8n Expression Syntax** - Configure expression fields
|
||||||
|
- **n8n Workflow Patterns** - Apply patterns with proper configuration
|
||||||
Reference in New Issue
Block a user