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.
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) *ReverseProxyThe 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
