Go Code Generation

Generate high-performance Go code from your visual workflows with goroutines, channels, and comprehensive helper libraries.

Installation

Requirements

  • Go 1.19+
  • Node.js for Code nodes
  • Modules: go mod tidy
go mod tidy
# For Code nodes:
go get github.com/dop251/goja  # JavaScript engine

Environment Variables

export OPENAI_API_KEY=your_openai_api_key_here

Usage Example

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "sync"
    
    "github.com/your-org/workflow/helpers"
    "github.com/your-org/workflow/ui"
)

// Generated function with parallel execution (example)
func myWorkflow(input map[string]interface{}) (map[string]interface{}, error) {
    data := input
    if data == nil {
        data = make(map[string]interface{})
    }
    
    // Initial HTTP request
    result, err := helpers.HTTPRequest("https://api.example.com/data", nil)
    if err != nil {
        return nil, err
    }
    data = result
    
    // Fork node - parallel execution
    var wg sync.WaitGroup
    var branch1Result, branch2Result map[string]interface{}
    var err1, err2 error
    
    wg.Add(2)
    
    // Branch 1: AI analysis
    go func() {
        defer wg.Done()
        analysis, err := helpers.CallAI("Analyze items", "gpt-4o-mini", map[string]interface{}{})
        if err != nil {
            err1 = err
            return
        }
        branch1Result = map[string]interface{}{"analysis": analysis}
    }()
    
    // Branch 2: Data processing with JavaScript
    go func() {
        defer wg.Done()
        jsCode := `
        data.processed = data.items.map(item => ({
            ...item,
            processed: true,
            timestamp: new Date().toISOString()
        }));
        `
        result, err := helpers.ExecuteJavaScript(jsCode, data)
        if err != nil {
            err2 = err
            return
        }
        branch2Result = result
    }()
    
    wg.Wait()
    
    // Check for errors
    if err1 != nil {
        return nil, err1
    }
    if err2 != nil {
        return nil, err2
    }
    
    // Join results
    for key, value := range branch1Result {
        data[key] = value
    }
    for key, value := range branch2Result {
        data[key] = value
    }
    
    // Show completion
    ui.ShowMessage("Workflow completed successfully", "success")
    
    return data, nil
}

func main() {
    input := map[string]interface{}{
        "items": []interface{}{
            map[string]interface{}{"id": "1", "name": "Item 1"},
            map[string]interface{}{"id": "2", "name": "Item 2"},
        },
    }
    
    result, err := myWorkflow(input)
    if err != nil {
        log.Fatal(err)
    }
    
    // Pretty print result
    jsonResult, _ := json.MarshalIndent(result, "", "  ")
    fmt.Printf("Result:\n%s\n", jsonResult)
}

Code Nodes

Go uses ExecuteJavaScript() for Code nodes:

// JavaScript code execution in Go
jsCode := `
data.processed = data.items.map(item => ({
    ...item,
    processed: true,
    timestamp: new Date().toISOString()
}));
`

result, err := helpers.ExecuteJavaScript(jsCode, data)
if err != nil {
    return nil, fmt.Errorf("JavaScript execution failed: %w", err)
}

Parallel Execution

Fork/join nodes use goroutines and WaitGroups:

// Fork node - parallel execution
var wg sync.WaitGroup
results := make([]map[string]interface{}, 2)
errors := make([]error, 2)

wg.Add(2)

// Branch 1
go func() {
    defer wg.Done()
    result, err := helpers.HTTPRequest("https://api1.example.com/data", nil)
    results[0] = result
    errors[0] = err
}()

// Branch 2  
go func() {
    defer wg.Done()
    result, err := helpers.CallAI("Process data", "gpt-4o-mini", nil)
    results[1] = map[string]interface{}{"analysis": result}
    errors[1] = err
}()

wg.Wait()

// Check for errors
for i, err := range errors {
    if err != nil {
        return nil, fmt.Errorf("branch %d failed: %w", i+1, err)
    }
}

// Merge results
mergedData := make(map[string]interface{})
for _, result := range results {
    for key, value := range result {
        mergedData[key] = value
    }
}

Helper Functions

HTTP Requests

// GET request
data, err := helpers.HTTPRequest("https://api.example.com/users", nil)
if err != nil {
    return nil, err
}

// POST with data
options := &helpers.HTTPOptions{
    Method: "POST",
    Headers: map[string]string{
        "Content-Type": "application/json",
        "Authorization": "Bearer token",
    },
    Body: map[string]interface{}{
        "name": "John",
        "email": "john@example.com",
    },
}

result, err := helpers.HTTPRequest("https://api.example.com/users", options)

AI Calls

// Simple AI call
response, err := helpers.CallAI("Summarize this text", "gpt-4o-mini", nil)
if err != nil {
    return nil, err
}

// Advanced AI call with options
options := map[string]interface{}{
    "temperature": 0.7,
    "max_tokens": 500,
}
analysis, err := helpers.CallAI("Analyze sentiment", "gpt-4", options)

Template Variables

text := "Hello {{name}}, your order {{orderId}} is ready"
context := map[string]interface{}{
    "name": "John",
    "orderId": "12345",
}

result := helpers.ReplaceTemplateVariables(text, context)
// Result: "Hello John, your order 12345 is ready"

Deployment Options

Standalone Binary

# Build for current platform
go build -o workflow workflow.go

# Cross-compile for Linux
GOOS=linux GOARCH=amd64 go build -o workflow-linux workflow.go

# Cross-compile for Windows
GOOS=windows GOARCH=amd64 go build -o workflow.exe workflow.go

Docker Container

# Multi-stage build
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN go build -o workflow

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/workflow ./
CMD ["./workflow"]

HTTP Server

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

func workflowHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    
    var input map[string]interface{}
    if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }
    
    result, err := myWorkflow(input)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(result)
}

func main() {
    http.HandleFunc("/workflow", workflowHandler)
    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Testing

package main

import (
    "testing"
    "reflect"
)

func TestMyWorkflow(t *testing.T) {
    input := map[string]interface{}{
        "items": []interface{}{
            map[string]interface{}{"id": "1", "name": "Test"},
        },
    }
    
    result, err := myWorkflow(input)
    if err != nil {
        t.Fatalf("Workflow failed: %v", err)
    }
    
    if result["processed"] == nil {
        t.Error("Expected processed field")
    }
}

func TestEmptyInput(t *testing.T) {
    result, err := myWorkflow(nil)
    if err != nil {
        t.Fatalf("Workflow failed with empty input: %v", err)
    }
    
    if result == nil {
        t.Error("Expected non-nil result")
    }
}

Error Handling

import "errors"

// Custom error types
var (
    ErrInvalidInput = errors.New("invalid input data")
    ErrNetworkError = errors.New("network request failed")
    ErrProcessingError = errors.New("data processing failed")
)

func myWorkflow(input map[string]interface{}) (map[string]interface{}, error) {
    if input == nil {
        return nil, ErrInvalidInput
    }
    
    data, err := helpers.HTTPRequest(url, options)
    if err != nil {
        return nil, fmt.Errorf("%w: %v", ErrNetworkError, err)
    }
    
    // Continue processing...
    return data, nil
}

Performance Tips

  1. Goroutine Pools: For high-throughput scenarios
  2. Context Cancellation: Use context.Context for timeout handling
  3. Memory Management: Reuse slices and maps where possible
  4. Profiling: Use pprof for performance analysis
import "context"

func myWorkflowWithContext(ctx context.Context, input map[string]interface{}) (map[string]interface{}, error) {
    // Check context cancellation
    select {
    case <-ctx.Done():
        return nil, ctx.Err()
    default:
    }
    
    // Continue with workflow...
}