Build a Simple Go API Gateway with net/http ReverseProxy

This article walks through creating a lightweight API gateway in Go using the standard net/http/httputil ReverseProxy, explains its core concepts, compares it with other gateway solutions, and provides a complete, runnable example that routes authentication and user services.

Go Development Architecture Practice
Go Development Architecture Practice
Go Development Architecture Practice
Build a Simple Go API Gateway with net/http ReverseProxy

In a recent microservice project that uses go-kit for backend development, a simple API gateway was needed. Instead of adopting a heavyweight framework, the author chose to implement the gateway directly in Go.

What an API Gateway Does

An API gateway acts as the single entry point for a system, encapsulating internal architecture and presenting a tailored API to each client. It can also handle authentication, monitoring, load balancing, caching, request splitting, static responses, and more.

Common approaches to building an API gateway include generic reverse proxies (e.g., Nginx, HAProxy), network programming frameworks (e.g., Netty, Servlet), and dedicated gateway frameworks (e.g., Spring Cloud Gateway, Zuul, Zuul2). The most basic function—reverse proxying—can be achieved with Go’s standard library.

Using Go’s net/http/httputil ReverseProxy

The net/http/httputil package provides the ReverseProxy type and the helper function NewSingleHostReverseProxy. The function creates a proxy that forwards incoming requests to a target URL, adjusting the scheme, host, and base path while preserving the original request’s query string.

func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy

The ReverseProxy struct contains several fields, the most important being Director and ModifyResponse. When a request arrives, ServeHTTP first calls Director to rewrite the request (e.g., change the target address or headers), then forwards it. After receiving the response, ModifyResponse can adjust the response before it is sent back to the client.

type ReverseProxy struct {
    Director       func(*http.Request)
    Transport      http.RoundTripper
    FlushInterval  time.Duration
    ErrorLog       *log.Logger
    BufferPool     BufferPool
    ModifyResponse func(*http.Response) error
    ErrorHandler   func(http.ResponseWriter, *http.Request, error)
}

Because NewSingleHostReverseProxy already sets up a suitable Director, using it is as simple as passing the target server’s URL.

Complete Example

The example below demonstrates a gateway that routes requests to two microservices: /api/auth and /api/user . It can be extended to handle additional services as needed.
package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strings"
)

type handle struct {
    host string
    port string
}

type Service struct {
    auth *handle
    user *handle
}

func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    var remote *url.URL
    if strings.Contains(r.RequestURI, "api/auth") {
        remote, _ = url.Parse("http://" + s.auth.host + ":" + s.auth.port)
    } else if strings.Contains(r.RequestURI, "api/user") {
        remote, _ = url.Parse("http://" + s.user.host + ":" + s.user.port)
    } else {
        fmt.Fprintf(w, "404 Not Found")
        return
    }
    proxy := httputil.NewSingleHostReverseProxy(remote)
    proxy.ServeHTTP(w, r)
}

func startServer() {
    // Register the backend services (host, port)
    service := &Service{
        auth: &handle{host: "127.0.0.1", port: "8081"},
        user: &handle{host: "127.0.0.1", port: "8082"},
    }
    err := http.ListenAndServe(":8888", service)
    if err != nil {
        log.Fatalln("ListenAndServe: ", err)
    }
}

func main() {
    startServer()
}

Running this program starts a gateway on port 8888. Requests matching /api/auth are proxied to 127.0.0.1:8081, while those matching /api/user go to 127.0.0.1:8082. Any other path receives a 404 response.

This straightforward approach shows how Go’s standard library can be leveraged to build a functional API gateway without external dependencies, making it suitable for simple microservice setups.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

microservicesGoapi-gatewaynet/httpReverseProxy
Go Development Architecture Practice
Written by

Go Development Architecture Practice

Daily sharing of Golang-related technical articles, practical resources, language news, tutorials, real-world projects, and more. Looking forward to growing together. Let's go!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.