1. Goalο
Build
n8n-nodes-zyra
, a custom n8n node package that:Wraps Zyra FastAPI calls.
Exposes one node type per CLI module: Acquire, Process, Visualize, Decimate.
Dynamically loads available commands for each module from the API.
Returns execution logs and exit codes to the workflow.
Enables conditional branching and error handling in n8n.
2. Node Package Structureο
n8n-nodes-zyra/
package.json
credentials/
zyraApi.credentials.ts
nodes/
Acquire.node.ts
Process.node.ts
Visualize.node.ts
Decimate.node.ts
README.md
3. Credentialsο
zyraApi.credentials.ts
Stores:
Base URL of the FastAPI service.
API key (if authentication enabled).
Used in all node types.
4. Node Typesο
4.1 Acquire Nodeο
Dropdown: command list from
/cli/commands?stage=acquire
.Dynamic parameter fields based on selected command.
Sends POST to
/cli/run
withstage="acquire"
.
4.2 Process Nodeο
Dropdown:
/cli/commands?stage=process
.Conditional parameter UI.
Sends POST with
stage="process"
.
4.3 Visualize Nodeο
Dropdown:
/cli/commands?stage=visualize
.Visualization-specific args shown dynamically.
Sends POST with
stage="visualize"
.
4.4 Decimate Nodeο
Dropdown:
/cli/commands?stage=decimate
.Destination-specific args shown dynamically.
Sends POST with
stage="decimate"
.
5. Execution Logic with Logs & Exit Codeο
Each node:
Calls
/cli/run
(sync or async mode).Receives:
{
"status": "success",
"stdout": "...",
"stderr": "...",
"exit_code": 0
}
Returns this to n8n output as:
{
"stage": "process",
"command": "decode-grib2",
"args": {...},
"exit_code": 0,
"stdout": "...",
"stderr": "...",
"timestamp": "2025-08-12T15:32:10Z"
}
Example execute()
snippet:
const creds = await this.getCredentials('zyraApi');
const response = await this.helpers.httpRequest({
method: 'POST',
url: `${creds.baseUrl}/cli/run`,
headers: { Authorization: `Bearer ${creds.apiKey}` },
body: {
stage: 'process',
command: this.getNodeParameter('command', 0),
args: this.getNodeParameter('args', 0, {}),
mode: 'sync'
},
json: true
});
return [this.helpers.returnJsonArray({
stage: 'process',
command: this.getNodeParameter('command', 0),
args: this.getNodeParameter('args', 0, {}),
exit_code: response.exit_code,
stdout: response.stdout,
stderr: response.stderr,
timestamp: new Date().toISOString()
})];
6. Dynamic Command Loadingο
API endpoint
/cli/commands
:
{
"acquire": ["http", "s3", "ftp", "vimeo"],
"process": ["decode-grib2", "convert-format", "extract-variable"],
"visualize": ["plot", "colormap"],
"decimate": ["local", "s3", "ftp"]
}
n8n node fetches commands for its stage when rendering parameter dropdown.
7. Debugging in n8nο
Branch on Success/Failure:
Use
If
node to checkexit_code
.
View Logs:
stdout
andstderr
appear in n8n execution data.
Error Notifications:
Connect failure branch to Slack, Email, etc.
8. Bonus Featuresο
Async Job Mode:
Node triggers
/cli/run
withmode="async"
.Poll
/jobs/{job_id}
until complete.
Upload Node:
Wrap
/upload
endpoint for local file ingestion.
Pipeline Runner Node:
Send entire pipeline YAML to
/run
.
9. Advantages of One Node Per Moduleο
Minimal number of nodes (4 core types).
Easy to maintain β adding a CLI command only updates API output.
Dynamic parameters keep UI relevant and avoid clutter.
Clear mapping to Zyra CLI structure.
10. Future Extensionο
Auto-generate βshortcutβ nodes for high-use functions.
Allow saving n8n workflows as Zyra pipeline configs.
Visualization Nodeο
Purpose: Render visual outputs from processed or raw data using the Zyra visualization module.
CLI Stage: visualize
Supported Commands: Dynamically fetched from /cli/commands?stage=visualize
, e.g.:
heatmap
contour
timeseries
wind-particles
(future)animate
(future)
Parameters:
Input file (
input
)Output path (
output
)Visualization type-specific parameters (
--var
,--levels
,--cmap
,--map-type
, etc.)
Example API Payload:
{
"stage": "visualize",
"command": "heatmap",
"params": {
"input": "processed.nc",
"var": "temperature",
"output": "heatmap.png",
"cmap": "viridis"
}
}
Output:
Image or animation file path.
Logs and exit code captured for debugging.