Skip to main content
Glama
n8n-client.js11 kB
import fetch from 'node-fetch'; import fs from 'fs'; import path from 'path'; /** * n8n REST API Client * Provides programmatic access to n8n workflow automation platform */ export class N8nClient { constructor(n8nURL, apiKey = null, username = null, password = null) { this.baseURL = n8nURL.replace(/\/$/, ''); // Remove trailing slash this.apiKey = apiKey; this.username = username; this.password = password; this.authToken = null; } /** * Get authentication headers for API requests */ getAuthHeaders() { const headers = { 'Content-Type': 'application/json' }; if (this.apiKey) { headers['X-N8N-API-KEY'] = this.apiKey; } else if (this.authToken) { headers['Authorization'] = `Bearer ${this.authToken}`; } return headers; } /** * Authenticate using username/password (if no API key) */ async authenticate() { if (this.apiKey) { console.log('✅ Using n8n API key authentication'); return true; } if (!this.username || !this.password) { throw new Error('Either API key or username/password required for n8n authentication'); } try { const response = await fetch(`${this.baseURL}/rest/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.username, password: this.password }) }); if (!response.ok) { throw new Error(`Authentication failed: ${response.statusText}`); } const data = await response.json(); this.authToken = data.data?.token; if (this.authToken) { console.log('✅ n8n authentication successful'); return true; } else { throw new Error('No token received from n8n'); } } catch (error) { console.error('❌ n8n authentication failed:', error.message); return false; } } /** * Make authenticated API request */ async makeRequest(endpoint, options = {}) { const url = `${this.baseURL}/rest${endpoint}`; const headers = { ...this.getAuthHeaders(), ...options.headers }; try { const response = await fetch(url, { ...options, headers }); if (!response.ok) { throw new Error(`API request failed: ${response.status} ${response.statusText}`); } const data = await response.json(); return { success: true, data: data.data || data }; } catch (error) { return { success: false, error: error.message }; } } /** * Get all workflows */ async getWorkflows() { return await this.makeRequest('/workflows'); } /** * Get specific workflow by ID */ async getWorkflow(workflowId) { return await this.makeRequest(`/workflows/${workflowId}`); } /** * Create a new workflow */ async createWorkflow(workflowData) { return await this.makeRequest('/workflows', { method: 'POST', body: JSON.stringify(workflowData) }); } /** * Update existing workflow */ async updateWorkflow(workflowId, workflowData) { return await this.makeRequest(`/workflows/${workflowId}`, { method: 'PUT', body: JSON.stringify(workflowData) }); } /** * Delete workflow */ async deleteWorkflow(workflowId) { return await this.makeRequest(`/workflows/${workflowId}`, { method: 'DELETE' }); } /** * Activate/deactivate workflow */ async setWorkflowStatus(workflowId, active) { return await this.makeRequest(`/workflows/${workflowId}/${active ? 'activate' : 'deactivate'}`, { method: 'POST' }); } /** * Execute workflow manually */ async executeWorkflow(workflowId, inputData = {}) { return await this.makeRequest(`/workflows/${workflowId}/execute`, { method: 'POST', body: JSON.stringify(inputData) }); } /** * Get workflow execution history */ async getExecutions(workflowId = null, limit = 20) { const params = new URLSearchParams(); if (workflowId) params.append('workflowId', workflowId); params.append('limit', limit.toString()); return await this.makeRequest(`/executions?${params}`); } /** * Get installed community nodes */ async getCommunityNodes() { return await this.makeRequest('/community-packages'); } /** * Install community node package */ async installCommunityNode(packageName, version = 'latest') { const packageSpec = version === 'latest' ? packageName : `${packageName}@${version}`; return await this.makeRequest('/community-packages', { method: 'POST', body: JSON.stringify({ name: packageSpec }) }); } /** * Uninstall community node package */ async uninstallCommunityNode(packageName) { return await this.makeRequest(`/community-packages/${packageName}`, { method: 'DELETE' }); } /** * Update community node package */ async updateCommunityNode(packageName, version = 'latest') { return await this.makeRequest(`/community-packages/${packageName}`, { method: 'PATCH', body: JSON.stringify({ version: version }) }); } /** * Import workflow from JSON file */ async importWorkflowFromFile(filePath) { try { if (!fs.existsSync(filePath)) { throw new Error(`Workflow file not found: ${filePath}`); } const workflowContent = fs.readFileSync(filePath, 'utf8'); const workflowData = JSON.parse(workflowContent); // Ensure required fields if (!workflowData.name) { workflowData.name = path.basename(filePath, '.json'); } const result = await this.createWorkflow(workflowData); return { ...result, fileName: path.basename(filePath), imported: true }; } catch (error) { return { success: false, error: error.message }; } } /** * Export workflow to JSON file */ async exportWorkflowToFile(workflowId, outputPath = null) { try { const workflowResult = await this.getWorkflow(workflowId); if (!workflowResult.success) { return workflowResult; } const workflow = workflowResult.data; const fileName = outputPath || `${workflow.name || 'workflow'}_${workflowId}.json`; fs.writeFileSync(fileName, JSON.stringify(workflow, null, 2)); return { success: true, message: `Workflow exported successfully`, fileName: fileName, workflowName: workflow.name }; } catch (error) { return { success: false, error: error.message }; } } /** * Bulk import workflows from directory */ async importWorkflowsFromDirectory(directoryPath) { try { if (!fs.existsSync(directoryPath)) { throw new Error(`Directory not found: ${directoryPath}`); } const files = fs.readdirSync(directoryPath) .filter(file => file.endsWith('.json')); const results = []; for (const file of files) { const filePath = path.join(directoryPath, file); const result = await this.importWorkflowFromFile(filePath); results.push({ file: file, ...result }); } const successful = results.filter(r => r.success).length; const failed = results.filter(r => !r.success).length; return { success: failed === 0, message: `Imported ${successful} workflows successfully, ${failed} failed`, results: results, summary: { successful, failed, total: files.length } }; } catch (error) { return { success: false, error: error.message }; } } /** * Get available workflow templates from n8n community */ async getWorkflowTemplates(category = null, limit = 50) { try { // This would connect to n8n's template API // Note: Actual implementation depends on n8n's template API availability const params = new URLSearchParams(); if (category) params.append('category', category); params.append('limit', limit.toString()); return await this.makeRequest(`/workflows/templates?${params}`); } catch (error) { return { success: false, error: 'Template API not available in this n8n version', message: 'Consider using workflow import from QNAP storage instead' }; } } /** * Health check for n8n instance */ async healthCheck() { try { const response = await fetch(`${this.baseURL}/healthz`); const isHealthy = response.ok; return { success: true, healthy: isHealthy, status: response.status, message: isHealthy ? 'n8n instance is healthy' : 'n8n instance has issues' }; } catch (error) { return { success: false, healthy: false, error: error.message }; } } /** * Get n8n instance information */ async getInstanceInfo() { try { // Try to get settings/info endpoint const result = await this.makeRequest('/settings'); return result; } catch (error) { return { success: false, error: error.message }; } } } export default N8nClient;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bermingham85/mcp-puppet-pipeline'

If you have feedback or need assistance with the MCP directory API, please join our Discord server