2023-02-01 10:00:00+00:00

In a microservice architecture, managing cross-cutting concerns like routing, authentication, authorization, and rate limiting at each service level introduces duplicate code and maintenance overhead. The standard pattern to solve this is a Unified API Gateway. By handling these concerns at the edge of your infrastructure, downstream services can remain focused entirely on their core business logic.

When selecting a language to build an API gateway, Go stands out as an exceptional choice. Its lightweight goroutines, built-in net/http package, and memory efficiency make it ideal for high-throughput edge proxies.


1. Dynamic Reverse Proxying

Go's standard library provides a built-in reverse proxy implementation in the net/http/httputil package. We can utilize httputil.NewSingleHostReverseProxy to route incoming HTTP requests to their corresponding backend microservices based on prefix paths:

func NewGatewayProxy(targetURL string) *httputil.ReverseProxy {
    url, _ := url.Parse(targetURL)
    proxy := httputil.NewSingleHostReverseProxy(url)
    
    // Customize director to adjust headers
    originalDirector := proxy.Director
    proxy.Director = func(req *http.Request) {
        originalDirector(req)
        req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
        req.Header.Set("X-Gateway-Request-ID", uuid.New().String())
    }
    return proxy
}

2. Token-Bucket Rate Limiting

To protect downstream services from denial-of-service attempts and traffic spikes, we implement a middleware utilizing Go's golang.org/x/time/rate package. This implements the classic token-bucket algorithm:

type IPBasedLimiter struct {
    ips map[string]*rate.Limiter
    mu  sync.Mutex
    r   rate.Limit
    b   int
}

func (l *IPBasedLimiter) GetLimiter(ip string) *rate.Limiter {
    l.mu.Lock()
    defer l.mu.Unlock()
    
    limiter, exists := l.ips[ip]
    if !exists {
        limiter = rate.NewLimiter(l.r, l.b)
        l.ips[ip] = limiter
    }
    return limiter
}

By routing all requests through this gateway, we reduce latency overhead to sub-millisecond ranges while securing the internal network topology.