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
- Goroutine Pools: For high-throughput scenarios
- Context Cancellation: Use context.Context for timeout handling
- Memory Management: Reuse slices and maps where possible
- 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...
}