Skip to content

GrimBit1/node-go-proxy

Repository files navigation

Node-Go Reverse Proxy

A flexible Express middleware for reverse proxying requests between Node.js and Go services, designed to facilitate gradual migration from Node.js to Go applications.

Features

  • 🔄 Seamless Request Forwarding: Proxy HTTP requests with support for all methods (GET, POST, PUT, DELETE, etc.)
  • 📁 File Upload Support: Handle multipart/form-data with file uploads using multer
  • 📊 Request/Response Callbacks: Access request and response data for logging, analytics, or custom processing
  • 🚀 Streaming Support: Efficient streaming for large responses when no callback is needed
  • Zero-Downtime Migration: Gradually migrate routes from Node.js to Go without service interruption
  • 🛡️ Error Handling: Robust error handling with proper HTTP status codes
  • 🔧 Configurable: Environment-based configuration with sensible defaults

Installation

npm install

Quick Start

Basic Usage

import express from 'express';
import { expressMiddlewareProxy } from './express-middleware';

const app = express();

// Proxy all requests to Go service
app.use('/api', expressMiddlewareProxy({
  host: 'localhost',
  port: 8080
}));

app.listen(3000);

With Environment Variables

// Set environment variables
process.env.GO_HOST = 'localhost';
process.env.GO_PORT = '8080';

// Use defaults from environment
app.use('/api', expressMiddlewareProxy());

With Callback for Analytics

app.use('/api/users', expressMiddlewareProxy(
  { host: 'localhost', port: 8080 },
  async (req, res, responseData) => {
    // Log request/response for analytics
    console.log(`${req.method} ${req.url} - ${res.statusCode}`);
    console.log('Response size:', responseData.length);
    
    // Save to analytics database
    await analytics.track({
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      responseSize: responseData.length
    });
  }
));

File Upload Proxy

import multer from 'multer';

const upload = multer({ dest: 'uploads/' });

app.post('/upload', 
  upload.fields([{ name: 'files', maxCount: 10 }]),
  expressMiddlewareProxy({
    host: 'localhost',
    port: 8080,
    path: '/upload'
  })
);

API Reference

expressMiddlewareProxy(options, callback?)

Options

Parameter Type Default Description
host string process.env.GO_HOST or 'localhost' Target server hostname
port number process.env.GO_PORT or 80 Target server port
path string req.url Target path (defaults to original request path)
method string req.method HTTP method (defaults to original request method)
headers object {} Additional headers to add to the proxied request

Callback Function

The optional callback function receives three parameters:

callback(req: CustomRequest, res: Response, responseData: string) => void | Promise<void>
  • req - Original Express request object
  • res - Express response object
  • responseData - Complete response data from the target server

Note: The callback is for computation only. It doesn't write to the response stream.

Use Cases

1. Gradual Migration

Perfect for migrating from Node.js to Go services incrementally:

// Migrate user service first
app.use('/api/users', expressMiddlewareProxy({ port: 8080 }));

// Keep other services in Node.js for now
app.use('/api/auth', authRoutes);
app.use('/api/orders', orderRoutes);

2. A/B Testing

Route traffic to different service versions:

app.use('/api/v2', expressMiddlewareProxy({ 
  port: process.env.NEW_SERVICE_PORT 
}));

3. Microservices Architecture

Route to different services based on path:

app.use('/api/users', expressMiddlewareProxy({ port: 8001 }));
app.use('/api/products', expressMiddlewareProxy({ port: 8002 }));
app.use('/api/orders', expressMiddlewareProxy({ port: 8003 }));

4. Request/Response Logging

Monitor and analyze traffic:

app.use('/api', expressMiddlewareProxy(
  { port: 8080 },
  async (req, res, data) => {
    await logger.info({
      timestamp: new Date(),
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      responseSize: data.length,
      userAgent: req.headers['user-agent']
    });
  }
));

Example Go Server

Here's a simple Go server that works with this proxy:

package main

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

func main() {
    http.HandleFunc("/", handleRequest)
    fmt.Println("Go server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // Read request body
    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // Echo back the request info
    response := map[string]interface{}{
        "method": r.Method,
        "path":   r.URL.Path,
        "body":   string(body),
        "headers": r.Header,
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(response)
}

Environment Variables

Variable Description Default
GO_HOST Target Go server hostname localhost
GO_PORT Target Go server port 80

Error Handling

The middleware handles various error scenarios:

  • Connection errors: Returns 502 Bad Gateway
  • Timeout errors: Returns 504 Gateway Timeout
  • Invalid responses: Returns 500 Internal Server Error

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Built for gradual Node.js to Go migration scenarios
  • Inspired by the need for zero-downtime service transitions
  • Designed with production reliability in mind

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors