Why a Built-In Gateway
Most Go services eventually need a reverse proxy, rate limiter, or circuit breaker in front of their upstream dependencies. Instead of deploying a separate Nginx, Envoy, or Kong instance, Forge ships a gateway extension that runs in-process — same binary, same observability, same configuration system.
Basic Setup
Enable the gateway extension and define upstream routes:
app := forge.New()
app.Use(gateway.Extension(
gateway.WithRoutes(
gateway.Route{
Path: "/api/users/*",
Upstream: "http://user-service:8080",
},
gateway.Route{
Path: "/api/orders/*",
Upstream: "http://order-service:8080",
},
),
))
app.Start()Load Balancing
Distribute traffic across multiple upstream instances with built-in load balancing strategies:
gateway.Route{
Path: "/api/users/*",
Upstreams: []string{
"http://user-service-1:8080",
"http://user-service-2:8080",
"http://user-service-3:8080",
},
LoadBalancer: gateway.RoundRobin(), // or WeightedRoundRobin, LeastConnections, Random
}Health checks run in the background and automatically remove unhealthy upstreams from the rotation.
Circuit Breaking
Protect your services from cascading failures with circuit breakers:
gateway.Route{
Path: "/api/payments/*",
Upstream: "http://payment-service:8080",
CircuitBreaker: gateway.CircuitBreakerConfig{
MaxFailures: 5, // Open after 5 consecutive failures
Timeout: 30 * time.Second, // Try again after 30s
HalfOpenMax: 2, // Allow 2 test requests in half-open state
},
}When the circuit is open, the gateway returns a 503 Service Unavailable immediately instead of waiting for the upstream to timeout.
Rate Limiting
Apply rate limits per client, per route, or globally:
gateway.Route{
Path: "/api/*",
Upstream: "http://backend:8080",
RateLimiter: gateway.RateLimiterConfig{
Strategy: gateway.SlidingWindow,
Limit: 100, // 100 requests
Window: 1 * time.Minute, // per minute
KeyFunc: gateway.ByClientIP, // per client IP
Store: gateway.RedisStore(redisClient), // distributed counter
},
}When the limit is exceeded, the gateway returns a 429 Too Many Requests response with Retry-After and X-RateLimit-* headers.
Request/Response Transformation
Modify requests and responses as they pass through the gateway:
gateway.Route{
Path: "/api/v2/*",
Upstream: "http://backend:8080",
RequestTransform: func(req *http.Request) {
req.Header.Set("X-Gateway-Version", "2.0")
req.URL.Path = strings.TrimPrefix(req.URL.Path, "/api/v2")
},
ResponseTransform: func(resp *http.Response) {
resp.Header.Set("X-Served-By", "forge-gateway")
},
}Observability
The gateway extension automatically integrates with Forge's observability stack:
- Prometheus metrics — Request count, latency histograms, error rates per route
- Distributed tracing — Trace headers propagated to upstreams
- Structured logging — Request/response logs with correlation IDs
- Health endpoint — Aggregated health of all upstream services
app.Use(gateway.Extension(
gateway.WithMetrics(true),
gateway.WithTracing(true),
gateway.WithAccessLog(true),
))All of these features compose naturally with the rest of your Forge application. The gateway runs alongside your application routes, shares the same DI container, and benefits from the same graceful shutdown and health check infrastructure.