Skip to main content

Proxy

Proxy forwards requests through httputil.ReverseProxy.

app.UsePrefix("/upstream", middleware.Proxy("https://api.example.com"))

The simple constructor is the right default for a single upstream. Zinc rewrites the request scheme, host, and path through the standard library reverse proxy.

Use ProxyWithConfig when the request or response needs adjustment.

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Target: "https://api.example.com",
Director: func(req *http.Request) {
req.Header.Set("X-Forwarded-App", "zinc")
},
Modify: func(resp *http.Response) error {
resp.Header.Del("Server")
return nil
},
}))

Modify is kept for compatibility. New code can use ModifyResponse; both are chained when both are set.

Multiple targets

Proxy can balance across multiple targets. Targets uses round-robin by default.

apiA, _ := url.Parse("https://api-a.example.com")
apiB, _ := url.Parse("https://api-b.example.com")

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Targets: []*middleware.ProxyTarget{
{Name: "a", URL: apiA},
{Name: "b", URL: apiB},
},
}))

Use an explicit balancer when the choice should be obvious from the config.

targets := []*middleware.ProxyTarget{
{Name: "a", URL: apiA},
{Name: "b", URL: apiB},
}

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: middleware.NewRoundRobinBalancer(targets),
}))

For random target selection:

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Balancer: middleware.NewRandomBalancer(targets),
}))

Rewrites

Use Rewrite for exact paths or * suffix rules.

app.UsePrefix("/api", middleware.ProxyWithConfig(middleware.ProxyConfig{
Target: "https://api.example.com",
Rewrite: map[string]string{
"/api/*": "/v1/*",
},
}))

Use RegexRewrite when wildcard rules are not expressive enough.

app.UsePrefix("/api", middleware.ProxyWithConfig(middleware.ProxyConfig{
Target: "https://api.example.com",
RegexRewrite: map[*regexp.Regexp]string{
regexp.MustCompile(`^/api/users/(\d+)$`): "/v1/users/$1",
},
}))

Retries

Retries are opt-in.

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Target: "https://api.example.com",
Retries: 2,
RetryFilter: func(c *zinc.Context, err error) bool {
return c.Method() == zinc.MethodGet
},
}))

Zinc only retries when the request body can be replayed safely: no body, http.NoBody, or a request with GetBody configured.

Transport

Pass a custom transport for timeouts, tracing, connection pools, or tests.

app.Use(middleware.ProxyWithConfig(middleware.ProxyConfig{
Target: "https://api.example.com",
Transport: customTransport,
}))

The target must be a valid absolute URL.