DevPill #9 - IP Based Rate Limiter Middleware for native Go REST API

Published: (December 11, 2025 at 03:54 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Function to get the right remote address IP

Usually we use the RemoteAddr field of http.Request to get the remote address, but in cloud environments (e.g., Kubernetes ingress) it may not contain the correct client IP. The function below checks the X-Forwarded-For header first and falls back to RemoteAddr if necessary.

func GetClientIP(r *http.Request) string {
    // In Kubernetes ingress or other cloud services, r.RemoteAddr might not work.
    // Get the client IP using the X-Forwarded-For header.
    forwarded := r.Header.Get("X-Forwarded-For")
    if forwarded != "" {
        parts := strings.Split(forwarded, ",")
        return strings.TrimSpace(parts[0])
    }

    // Fallback to RemoteAddr.
    ip, _, _ := net.SplitHostPort(r.RemoteAddr)
    return ip
}

Storing rate limiters per visitor

A map is used to store a rate.Limiter for each unique IP address. Access to the map is synchronized with a mutex.

var (
    visitors = make(map[string]*rate.Limiter)
    mu       sync.Mutex
)

func getLimiter(ip string) *rate.Limiter {
    mu.Lock()
    defer mu.Unlock()

    limiter, exists := visitors[ip]
    if !exists {
        // 1 request per second with a burst of 3.
        limiter = rate.NewLimiter(1, 3)
        visitors[ip] = limiter
    }
    return limiter
}

IP‑based rate limiter middleware

The middleware obtains the client IP, retrieves (or creates) its limiter, and checks whether the request is allowed. If the limit is exceeded, it returns 429 Too Many Requests.

func IPBasedRateLimiter(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip := GetClientIP(r)

        limiter := getLimiter(ip)

        if !limiter.Allow() {
            http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
            return
        }

        next.ServeHTTP(w, r)
    })
}
Back to Blog

Related posts

Read more »

GO profiling using pprof

What is pprof? pprof is Go's built‑in profiling tool that allows you to collect and analyze runtime data from your application, such as CPU usage, memory alloc...