Implements the top-level httpx.Client that composes the full chain: Logging → User Middlewares → Retry → Circuit Breaker → Balancer → Transport - Response wrapper with JSON/XML/Bytes decoding and body caching - NewJSONRequest helper with Content-Type and GetBody support - Functional options: WithBaseURL, WithTimeout, WithRetry, WithEndpoints, etc. - Integration tests covering retry, balancing, error mapping, and JSON round-trips
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package httpx
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.codelab.vc/pkg/httpx/balancer"
|
|
"git.codelab.vc/pkg/httpx/circuitbreaker"
|
|
"git.codelab.vc/pkg/httpx/middleware"
|
|
"git.codelab.vc/pkg/httpx/retry"
|
|
)
|
|
|
|
type clientOptions struct {
|
|
baseURL string
|
|
timeout time.Duration
|
|
transport http.RoundTripper
|
|
logger *slog.Logger
|
|
errorMapper ErrorMapper
|
|
middlewares []middleware.Middleware
|
|
retryOpts []retry.Option
|
|
enableRetry bool
|
|
cbOpts []circuitbreaker.Option
|
|
enableCB bool
|
|
endpoints []balancer.Endpoint
|
|
balancerOpts []balancer.Option
|
|
}
|
|
|
|
// Option configures a Client.
|
|
type Option func(*clientOptions)
|
|
|
|
// WithBaseURL sets the base URL prepended to all relative request paths.
|
|
func WithBaseURL(url string) Option {
|
|
return func(o *clientOptions) { o.baseURL = url }
|
|
}
|
|
|
|
// WithTimeout sets the overall request timeout.
|
|
func WithTimeout(d time.Duration) Option {
|
|
return func(o *clientOptions) { o.timeout = d }
|
|
}
|
|
|
|
// WithTransport sets the base http.RoundTripper. Defaults to http.DefaultTransport.
|
|
func WithTransport(rt http.RoundTripper) Option {
|
|
return func(o *clientOptions) { o.transport = rt }
|
|
}
|
|
|
|
// WithLogger enables structured logging of requests and responses.
|
|
func WithLogger(l *slog.Logger) Option {
|
|
return func(o *clientOptions) { o.logger = l }
|
|
}
|
|
|
|
// WithErrorMapper sets a function that maps HTTP responses to errors.
|
|
func WithErrorMapper(m ErrorMapper) Option {
|
|
return func(o *clientOptions) { o.errorMapper = m }
|
|
}
|
|
|
|
// WithMiddleware appends user middlewares to the chain.
|
|
// These run between logging and retry in the middleware stack.
|
|
func WithMiddleware(mws ...middleware.Middleware) Option {
|
|
return func(o *clientOptions) { o.middlewares = append(o.middlewares, mws...) }
|
|
}
|
|
|
|
// WithRetry enables retry with the given options.
|
|
func WithRetry(opts ...retry.Option) Option {
|
|
return func(o *clientOptions) {
|
|
o.enableRetry = true
|
|
o.retryOpts = opts
|
|
}
|
|
}
|
|
|
|
// WithCircuitBreaker enables per-host circuit breaking.
|
|
func WithCircuitBreaker(opts ...circuitbreaker.Option) Option {
|
|
return func(o *clientOptions) {
|
|
o.enableCB = true
|
|
o.cbOpts = opts
|
|
}
|
|
}
|
|
|
|
// WithEndpoints sets the endpoints for load balancing.
|
|
func WithEndpoints(eps ...balancer.Endpoint) Option {
|
|
return func(o *clientOptions) { o.endpoints = eps }
|
|
}
|
|
|
|
// WithBalancer configures the load balancer strategy and options.
|
|
func WithBalancer(opts ...balancer.Option) Option {
|
|
return func(o *clientOptions) { o.balancerOpts = opts }
|
|
}
|