Documentation
¶
Overview ¶
Package httpx implements composable HTTP behavior as http.RoundTripper decorators: conditional caching, compression negotiation, and safe retry with backoff. Use them with an ordinary http.Client, standard requests and responses, and an existing transport's TLS, proxy and pool settings.
Transports first ¶
NewRetryTransport, NewCompressionTransport and NewCacheTransport each wrap one http.RoundTripper. NewChain combines layers into another RoundTripper; the first layer listed is innermost. Assign the result to http.Client.Transport and use http.NewRequestWithContext and client.Do. Request contexts, cookies, redirects, status codes and streaming bodies keep their standard net/http interfaces. Reuse clients and transports.
Put compression inside retry and cache outside retry. This lets fresh cache hits skip the network, while revalidation uses the retry policy and the cache stores decoded responses. If used, auth runs before cache lookup; rate limits, concurrency limits and breakers normally run per attempt.
HTTP caching ¶
CacheTransport is an opt-in private HTTP cache. It follows freshness, Cache-Control, Vary and identity boundaries, revalidates with ETag or Last-Modified, and merges a 304 response with the stored representation. MemoryCache bounds retained entries and bytes; CacheStore permits a custom store. Stale reuse is opt-in through origin directives or options.
Identity includes Authorization, Cookie, effective authority and configured identity headers. Configure all additional identity headers, including API-key headers; use separate stores for identities hidden in a transport, such as mTLS. Caller-conditional, ranged, HEAD and body-bearing GET requests bypass cache.
Compression and retry ¶
CompressionTransport negotiates gzip and deflate, with optional Brotli, and decodes supported complete response bodies lazily. Read errors remain body-read errors; partial representations keep their encoded bytes. Go's default transport already handles basic gzip; this layer supplies configurable accepted encodings and lazy decoding as a reusable decorator.
RetryTransport defaults to three total attempts with exponential backoff, jitter and Retry-After handling, subject to the request's deadline. Retry requires an idempotent method, an Idempotency-Key, or explicit WithRetryNonIdempotent permission, plus a replayable body. The server must implement deduplication for an idempotency key to make writes safe. Unknown streams are recorded as sent, within a bound, rather than buffered before the transport can honor cancellation.
Optional policies and helpers ¶
Circuit breakers, rate and concurrency limits, hedging, origin-bound auth, redacted logging and metrics are independent transports too. Their order determines whether they observe logical calls or individual attempts. TransportStack inspects layers; built-in layers expose Unwrap.
NewClient and NewStandard are optional builders returning *http.Client. Both default to a tuned base transport and 30-second timeout; NewStandard also enables compression and retry. Other policies must be enabled. Get, Post, Put, Patch and Do optionally decode bounded 2xx values by Content-Type. JSON and XML are built in; MessagePack and protobuf use separate modules. WithMaxResponseBytes defaults to 10 MiB after decompression. ReadAtMost bounds complete reads without typed decoding.
Status, bodies and shutdown ¶
A nil error is not an HTTP success check. Inspect the response status and close each response body, including one returned with a typed decode error. Raw client.Do bodies remain streaming and need application-owned bounds. EOF, read error or Close releases limiter slots and hedge winner contexts. Call CacheTransport.Close to stop background refreshes before closing idle transport connections with http.Client.CloseIdleConnections.
Optional modules ¶
Blank-import codec/msgpack, codec/proto or compress/brotli to register MessagePack, protobuf or Brotli. Named imports expose implementations. Each optional dependency is a separate Go module; the core depends only on golang.org/x/time and github.com/sony/gobreaker/v2.
Index ¶
- Constants
- Variables
- func DecodeResponse(resp *http.Response, codec Codec, v any, opts ...DecodeOption) error
- func Delete(ctx context.Context, client *http.Client, url string) (*http.Response, error)
- func Do[T any](client *http.Client, req *http.Request, opts ...DecodeOption) (T, *http.Response, error)
- func EncodeRequest(req *http.Request, codec Codec, v any) error
- func Get[T any](ctx context.Context, client *http.Client, url string, opts ...DecodeOption) (T, *http.Response, error)
- func HasCodec(contentType string) bool
- func HasCompressor(encoding string) bool
- func MustNewStandard(opts ...Option) *http.Client
- func NewBaseTransport(opts ...BaseOption) (*http.Transport, error)
- func NewClient(opts ...Option) (*http.Client, error)
- func NewStandard(opts ...Option) (*http.Client, error)
- func Patch[T any](ctx context.Context, client *http.Client, url string, body any, ...) (T, *http.Response, error)
- func Post[T any](ctx context.Context, client *http.Client, url string, body any, ...) (T, *http.Response, error)
- func Put[T any](ctx context.Context, client *http.Client, url string, body any, ...) (T, *http.Response, error)
- func ReadAtMost(r io.Reader, limit int64) ([]byte, error)
- func RegisterCodec(c Codec)
- func RegisterCompressor(encoding string, factory func() Compressor)
- func RegisteredEncodings() []string
- func TransportStack(client *http.Client) []http.RoundTripper
- type APIKeyProvider
- type AdaptiveHedgingTransport
- type AuthBinding
- type AuthProvider
- type AuthTransport
- type BaseOption
- func WithDialer(d *net.Dialer) BaseOption
- func WithDisableHTTP2() BaseOption
- func WithDisableKeepAlives() BaseOption
- func WithExpectContinueTimeout(d time.Duration) BaseOption
- func WithHTTP2() BaseOption
- func WithIdleConnTimeout(d time.Duration) BaseOption
- func WithMaxConnsPerHost(n int) BaseOption
- func WithMaxIdleConns(n int) BaseOption
- func WithMaxIdleConnsPerHost(n int) BaseOption
- func WithReadBufferSize(size int) BaseOption
- func WithResponseHeaderTimeout(d time.Duration) BaseOption
- func WithTLSConfig(cfg *tls.Config) BaseOption
- func WithTLSHandshakeTimeout(d time.Duration) BaseOption
- func WithWriteBufferSize(size int) BaseOption
- type BasicAuthProvider
- type BearerTokenProvider
- type BufferPool
- type CacheOption
- func WithCacheHook(hook MetricsHook) CacheOption
- func WithCacheIdentityHeaders(names ...string) CacheOption
- func WithMaxCacheBodyBytes(n int64) CacheOption
- func WithMaxRetention(d time.Duration) CacheOption
- func WithRevalidation(timeout time.Duration, concurrency int) CacheOption
- func WithStaleIfError(d time.Duration) CacheOption
- func WithStaleWhileRevalidate(d time.Duration) CacheOption
- type CacheStore
- type CacheTransport
- type CachedResponse
- type Chain
- type ChainAuthProvider
- type CircuitOption
- func WithFailureThreshold(n int) CircuitOption
- func WithIsFailure(fn func(*http.Response, error) bool) CircuitOption
- func WithMaxBreakers(n int) CircuitOption
- func WithOnStateChange(fn func(origin Origin, from, to State)) CircuitOption
- func WithOpenTimeout(d time.Duration) CircuitOption
- func WithSuccessThreshold(n int) CircuitOption
- type CircuitTransport
- type Codec
- type CompressionOption
- func WithBrotliLevel(level int) CompressionOption
- func WithCompressionPool(pool *BufferPool) CompressionOption
- func WithCompressor(encoding string, c Compressor) CompressionOption
- func WithDeflateLevel(level int) CompressionOption
- func WithEncodings(encodings ...string) CompressionOption
- func WithGzipLevel(level int) CompressionOption
- type CompressionTransport
- type Compressor
- type CountingHook
- func (h *CountingHook) OnCacheHit(_ *http.Request, _ bool)
- func (h *CountingHook) OnCacheMiss(_ *http.Request)
- func (h *CountingHook) OnRequest(*http.Request)
- func (h *CountingHook) OnResponse(_ *http.Request, _ *http.Response, _ time.Duration, err error)
- func (h *CountingHook) OnRetry(_ *http.Request, _ int, _ error)
- type DecodeOption
- type FuncAuthProvider
- type HedgingOption
- type HedgingTransport
- type LatencyHook
- func (h *LatencyHook) Avg() time.Duration
- func (h *LatencyHook) Count() int64
- func (h *LatencyHook) Max() time.Duration
- func (h *LatencyHook) Min() time.Duration
- func (h *LatencyHook) OnCacheHit(*http.Request, bool)
- func (h *LatencyHook) OnCacheMiss(*http.Request)
- func (h *LatencyHook) OnRequest(*http.Request)
- func (h *LatencyHook) OnResponse(_ *http.Request, _ *http.Response, duration time.Duration, _ error)
- func (h *LatencyHook) OnRetry(*http.Request, int, error)
- func (h *LatencyHook) Recent() []time.Duration
- func (h *LatencyHook) Reset()
- func (h *LatencyHook) Sum() time.Duration
- type LimiterOption
- type LimiterTransport
- func (t *LimiterTransport) Available() int
- func (t *LimiterTransport) Capacity() int
- func (t *LimiterTransport) CloseIdleConnections()
- func (t *LimiterTransport) InFlight() int
- func (t *LimiterTransport) RoundTrip(req *http.Request) (*http.Response, error)
- func (t *LimiterTransport) Unwrap() http.RoundTripper
- type LogEntry
- type LoggingHook
- type LoggingOption
- type LoggingTransport
- type MemoryCache
- type MemoryCacheOption
- type MetricsHook
- type MetricsTransport
- type MultiHook
- func (h *MultiHook) OnCacheHit(req *http.Request, fresh bool)
- func (h *MultiHook) OnCacheMiss(req *http.Request)
- func (h *MultiHook) OnRequest(req *http.Request)
- func (h *MultiHook) OnResponse(req *http.Request, resp *http.Response, duration time.Duration, err error)
- func (h *MultiHook) OnRetry(req *http.Request, attempt int, err error)
- func (h *MultiHook) OnRetryCause(req *http.Request, attempt int, cause RetryCause, err error)
- type Option
- func WithAuth(originURL string, provider AuthProvider) Option
- func WithBaseTransport(opts ...BaseOption) Option
- func WithCache(store CacheStore, opts ...CacheOption) Option
- func WithCircuitBreaker(opts ...CircuitOption) Option
- func WithCompression(opts ...CompressionOption) Option
- func WithHedging(delay time.Duration, opts ...HedgingOption) Option
- func WithJar(jar http.CookieJar) Option
- func WithLimiter(maxConcurrent int, opts ...LimiterOption) Option
- func WithLogging(hook LoggingHook, opts ...LoggingOption) Option
- func WithMetrics(hook MetricsHook) Option
- func WithRateLimit(rps float64, burst int, opts ...RateLimitOption) Option
- func WithRetry(opts ...RetryOption) Option
- func WithTimeout(d time.Duration) Option
- func WithTransport(t http.RoundTripper) Option
- type Origin
- type QueryParamAuthProvider
- type RateLimitOption
- type RateLimitTransport
- type RetryCause
- type RetryCauseHook
- type RetryOption
- func WithBackoff(initial, max time.Duration, multiplier float64) RetryOption
- func WithJitter(jitter float64) RetryOption
- func WithMaxAttempts(n int) RetryOption
- func WithMaxReplayBytes(n int64) RetryOption
- func WithRetryHook(hook MetricsHook) RetryOption
- func WithRetryIf(fn func(*http.Response, error) bool) RetryOption
- func WithRetryNonIdempotent() RetryOption
- func WithRetryOn(codes ...int) RetryOption
- type RetryTransport
- type State
- type StructuredLoggingHook
- type TransportFunc
- func WithAuthT(originURL string, provider AuthProvider) TransportFunc
- func WithCacheT(store CacheStore, opts ...CacheOption) TransportFunc
- func WithCircuitBreakerT(opts ...CircuitOption) TransportFunc
- func WithCompressionT(opts ...CompressionOption) TransportFunc
- func WithHedgingT(delay time.Duration, opts ...HedgingOption) TransportFunc
- func WithLimiterT(maxConcurrent int, opts ...LimiterOption) TransportFunc
- func WithLoggingT(hook LoggingHook, opts ...LoggingOption) TransportFunc
- func WithMetricsT(hook MetricsHook) TransportFunc
- func WithRateLimitT(rps float64, burst int, opts ...RateLimitOption) TransportFunc
- func WithRetryT(opts ...RetryOption) TransportFunc
Constants ¶
const ( DefaultMaxCacheBodyBytes int64 = 1 << 20 DefaultMaxRetention = 24 * time.Hour DefaultRevalidateTimeout = 30 * time.Second DefaultMaxConcurrentRevalidates = 8 )
Cache defaults.
const ( DefaultFailureThreshold = 5 DefaultSuccessThreshold = 2 DefaultOpenTimeout = 30 * time.Second )
Circuit breaker defaults.
const ( DefaultMemoryCacheMaxEntries = 1024 DefaultMemoryCacheMaxBytes int64 = 64 << 20 )
MemoryCache defaults.
const ( EncodingBrotli = "br" EncodingGzip = "gzip" EncodingDeflate = "deflate" EncodingZstd = "zstd" EncodingIdentity = "identity" )
Encoding constants for compression.
const ( ContentTypeJSON = "application/json" ContentTypeXML = "application/xml" ContentTypeMsgpack = "application/msgpack" ContentTypeProtobuf = "application/protobuf" ContentTypeFormURL = "application/x-www-form-urlencoded" ContentTypeOctetStream = "application/octet-stream" )
ContentType constants for codecs.
const DefaultLatencyWindow = 1024
DefaultLatencyWindow is how many recent latencies a LatencyHook keeps.
const DefaultMaxOrigins = 1024
DefaultMaxOrigins bounds how many origins CircuitTransport and RateLimitTransport keep state for.
const DefaultMaxReplayBytes int64 = 1 << 20
DefaultMaxReplayBytes is the largest request body RetryTransport records, as the first attempt sends it, so it can re-send it. Requests that set GetBody are replayed without recording; a larger body without GetBody, or one the first attempt did not read to its end, is not retried.
const DefaultMaxResponseBytes int64 = 10 << 20
DefaultMaxResponseBytes bounds how much of a response body the decoding helpers read.
const DefaultTimeout = 30 * time.Second
DefaultTimeout is the overall request timeout applied by NewClient when the caller passes no WithTimeout option. Set WithTimeout(0) to disable it (e.g., for long-poll endpoints); base transport timeouts still apply.
const IdempotencyKeyHeader = "Idempotency-Key"
IdempotencyKeyHeader is the request header that permits RetryTransport to replay a non-idempotent request. The server must implement deduplication for that key; setting it alone does not make a write safe.
const Redacted = "[REDACTED]"
Redacted replaces the value of every sensitive header and query parameter in the snapshots a LoggingTransport hands to its hook.
Variables ¶
var ( // ErrCircuitOpen is returned when the circuit breaker is open. ErrCircuitOpen = errors.New("httpx: circuit breaker is open") // ErrLimiterTimeout is returned when acquiring a slot times out. ErrLimiterTimeout = errors.New("httpx: limiter acquire timeout") // ErrResponseTooLarge is returned by the decoding helpers when a response // body exceeds WithMaxResponseBytes. ErrResponseTooLarge = errors.New("httpx: response body too large to decode") // ErrRateLimited is returned when the rate limit is exceeded. ErrRateLimited = errors.New("httpx: rate limit exceeded") // ErrAuthRefresh is returned when token refresh fails. ErrAuthRefresh = errors.New("httpx: auth token refresh failed") // ErrNoCodec is returned when no codec is registered for the response content type. ErrNoCodec = errors.New("httpx: no codec registered for content type") // ErrInvalidConfig is wrapped by every construction-time validation // failure returned from NewClient, NewStandard, NewBaseTransport, the // New*Transport constructors and Chain.Build. ErrInvalidConfig = errors.New("httpx: invalid configuration") )
Sentinel errors for transport failures.
Functions ¶
func DecodeResponse ¶
DecodeResponse reads resp.Body up to WithMaxResponseBytes (default DefaultMaxResponseBytes) and decodes it into v. Afterwards resp.Body holds the bytes read. A larger body fails with ErrResponseTooLarge and resp.Body still reads the whole body; the caller must close it. Unlike the typed request helpers, DecodeResponse does not check the status, request method or Content-Type; the caller selects the body and codec.
func Do ¶
func Do[T any](client *http.Client, req *http.Request, opts ...DecodeOption) (T, *http.Response, error)
Do executes a request and decodes the response body into T.
This is the lowest-level generic helper. Use it when you need full control over the request (custom headers, custom codec via EncodeRequest, etc.).
If the request has no Accept header, one is set from registered codecs. Only 2xx responses are decoded; non-2xx responses return zero T with the response body intact and nil error. The body is read up to WithMaxResponseBytes: a larger one fails with ErrResponseTooLarge and the returned response still reads the whole body, which the caller must close. After decoding (or a decode error) resp.Body holds the bytes read. When T is a pointer type the codec decodes into a newly allocated pointee. HEAD, 204 and 205 responses return zero T without decoding, even when their headers include a Content-Type.
req, _ := http.NewRequest("POST", url, nil)
httpx.EncodeRequest(req, msgpack.Codec, body)
user, resp, err := httpx.Do[User](client, req)
func EncodeRequest ¶
EncodeRequest encodes v into req's body, replacing any body req had: it closes the old one and sets Body, GetBody and ContentLength together, so a retry or a 307/308 redirect replays the new payload.
func Get ¶
func Get[T any](ctx context.Context, client *http.Client, url string, opts ...DecodeOption) (T, *http.Response, error)
Get sends a GET request and decodes the response body into T.
The codec is auto-detected from the response Content-Type using the global codec registry. Only 2xx responses are decoded; non-2xx responses return zero T with the response body intact and nil error. A body larger than WithMaxResponseBytes (default DefaultMaxResponseBytes) fails with ErrResponseTooLarge.
All transport decorators on the client (retry, auth, cache, compression, etc.) apply transparently.
user, resp, err := httpx.Get[User](ctx, client, "https://api.example.com/users/1")
func HasCompressor ¶
HasCompressor reports whether a compressor is registered for the encoding.
func MustNewStandard ¶
MustNewStandard is NewStandard for statically known options: it panics when they are invalid, like regexp.MustCompile. Use it only for zero-config defaults built from literal options; call NewStandard and handle the error whenever an option value comes from runtime configuration.
func NewBaseTransport ¶
func NewBaseTransport(opts ...BaseOption) (*http.Transport, error)
NewBaseTransport creates a tuned *http.Transport with production defaults.
Default configuration:
- MaxIdleConns: 100
- MaxIdleConnsPerHost: 10
- IdleConnTimeout: 90s
- TLSHandshakeTimeout: 10s
- ResponseHeaderTimeout: 30s (no per-request bound otherwise — a server that accepts the connection but never sends headers would hang the call)
- ForceAttemptHTTP2: true
- DisableCompression: true (compression is handled by CompressionTransport)
Negative counts, durations or buffer sizes and a nil dialer are rejected with an error wrapping ErrInvalidConfig.
func NewClient ¶
NewClient creates a new http.Client with the configured transport stack.
The stack order is fixed (see NewClient's build order below), independent of the order options are passed. Every enabled layer validates its configuration; the first invalid layer's error is returned, wrapping ErrInvalidConfig.
Example:
client, err := httpx.NewClient(
httpx.WithBaseTransport(httpx.WithHTTP2()),
httpx.WithCompression(),
httpx.WithRetry(httpx.WithMaxAttempts(3)),
httpx.WithCircuitBreaker(),
)
func NewStandard ¶
NewStandard returns an *http.Client with compression, safe retries and a bounded timeout for ordinary outbound API calls. Pass additional [Option]s to override or extend the defaults for a specific call site (e.g. circuit breaker around a flaky upstream, hedging for a latency-sensitive endpoint).
Default configuration:
- Base transport with HTTP/2 + tuned pool defaults (MaxIdleConns 100 / MaxIdleConnsPerHost 10 / IdleConnTimeout 90s / TLSHandshakeTimeout 10s / ResponseHeaderTimeout 30s)
- Compression (gzip and zlib deflate; optional registered encodings)
- Retry with exponential backoff (3 attempts; transient failures) for idempotent requests and requests carrying Idempotency-Key only — a POST or PATCH is sent once unless the caller opts in
- 30s overall request timeout
No HTTP cache is wired by default. Callers that want one opt in with WithCache, which partitions stored responses by Authorization, Cookie and any WithCacheIdentityHeaders. Configure all additional identity headers; identities hidden in a transport, such as mTLS, need separate stores.
Callers that need cancellation pass a context.Context with a deadline; the 30s ceiling is the upper bound, not the floor.
Codec note: httpx ships JSON + XML codecs natively. MsgPack is opt-in via the separate codec/msgpack module; protobuf uses codec/proto. Import only the formats your application needs.
NewStandard returns an error wrapping ErrInvalidConfig when an override is invalid; the defaults alone always validate.
func Patch ¶
func Patch[T any](ctx context.Context, client *http.Client, url string, body any, opts ...DecodeOption) (T, *http.Response, error)
Patch sends a PATCH request with an encoded body and decodes the response into T.
func Post ¶
func Post[T any](ctx context.Context, client *http.Client, url string, body any, opts ...DecodeOption) (T, *http.Response, error)
Post sends a POST request with an encoded body and decodes the response into T.
The body is encoded using the JSON codec by default. Pass nil for no body. If body implements io.Reader, it is used directly without encoding.
created, resp, err := httpx.Post[User](ctx, client, url, CreateUserReq{Name: "Alice"})
func Put ¶
func Put[T any](ctx context.Context, client *http.Client, url string, body any, opts ...DecodeOption) (T, *http.Response, error)
Put sends a PUT request with an encoded body and decodes the response into T.
updated, resp, err := httpx.Put[User](ctx, client, url, UpdateUserReq{Name: "Bob"})
func ReadAtMost ¶
ReadAtMost reads r to its end when it holds at most limit bytes. A larger input fails with ErrResponseTooLarge rather than returning a prefix, so a truncated representation is never mistaken for a whole one. limit must be at least 1.
func RegisterCodec ¶
func RegisterCodec(c Codec)
RegisterCodec registers a codec for its content type, replacing any earlier registration. Call it from init() in optional modules (e.g. codec/msgpack). It panics on a nil codec.
func RegisterCompressor ¶
func RegisterCompressor(encoding string, factory func() Compressor)
RegisterCompressor registers a compressor factory for an encoding, replacing any earlier registration. Call it from init() in optional modules (e.g. compress/brotli). It panics on a nil factory.
func RegisteredEncodings ¶
func RegisteredEncodings() []string
RegisteredEncodings returns the registered encoding names, sorted.
func TransportStack ¶
func TransportStack(client *http.Client) []http.RoundTripper
TransportStack returns the transport stack for inspection.
Types ¶
type APIKeyProvider ¶
APIKeyProvider adds an API key header.
func NewAPIKeyProvider ¶
func NewAPIKeyProvider(key string) *APIKeyProvider
NewAPIKeyProvider creates a new API key provider.
func NewAPIKeyProviderWithHeader ¶
func NewAPIKeyProviderWithHeader(key, header string) *APIKeyProvider
NewAPIKeyProviderWithHeader creates an API key provider with a custom header.
type AdaptiveHedgingTransport ¶
type AdaptiveHedgingTransport struct {
*HedgingTransport
// contains filtered or unexported fields
}
AdaptiveHedgingTransport adjusts hedge delay based on observed latencies.
func NewAdaptiveHedgingTransport ¶
func NewAdaptiveHedgingTransport(base http.RoundTripper, percentile float64, opts ...HedgingOption) (*AdaptiveHedgingTransport, error)
NewAdaptiveHedgingTransport creates a hedging transport that adapts delay based on latency.
percentile selects the observed latency used as the hedge delay and must be within (0, 1].
type AuthBinding ¶
type AuthBinding struct {
URL string
Provider AuthProvider
}
AuthBinding binds a provider to the origin of URL (its scheme, host and port; any path is ignored).
type AuthProvider ¶
AuthProvider adds authentication to requests.
type AuthTransport ¶
type AuthTransport struct {
// contains filtered or unexported fields
}
AuthTransport adds credentials to requests whose origin has a bound provider. The connection destination and effective Host authority must both match the binding before that provider runs, including on redirect hops followed by http.Client. Caller-supplied headers are passed through; this transport does not remove credentials already present on a request.
func NewAuthTransport ¶
func NewAuthTransport(base http.RoundTripper, bindings ...AuthBinding) (*AuthTransport, error)
NewAuthTransport creates a transport that applies each binding's provider only to requests for that binding's origin. At least one binding is required; origins must be distinct.
func (*AuthTransport) CloseIdleConnections ¶
func (t *AuthTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*AuthTransport) Unwrap ¶
func (t *AuthTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type BaseOption ¶
BaseOption configures a base transport.
func WithDialer ¶
func WithDialer(d *net.Dialer) BaseOption
WithDialer sets a custom dialer for establishing connections.
func WithDisableHTTP2 ¶
func WithDisableHTTP2() BaseOption
WithDisableHTTP2 disables HTTP/2, forcing HTTP/1.1.
func WithDisableKeepAlives ¶
func WithDisableKeepAlives() BaseOption
WithDisableKeepAlives disables HTTP keep-alives. This forces a new connection for each request.
func WithExpectContinueTimeout ¶
func WithExpectContinueTimeout(d time.Duration) BaseOption
WithExpectContinueTimeout sets how long the transport waits for a server's first response after sending request headers when the request had an "Expect: 100-continue" header (default: 1s).
func WithIdleConnTimeout ¶
func WithIdleConnTimeout(d time.Duration) BaseOption
WithIdleConnTimeout sets how long idle connections remain open.
func WithMaxConnsPerHost ¶
func WithMaxConnsPerHost(n int) BaseOption
WithMaxConnsPerHost limits the total number of connections per host. This includes dialing, active, and idle connections.
func WithMaxIdleConns ¶
func WithMaxIdleConns(n int) BaseOption
WithMaxIdleConns sets the maximum number of idle connections across all hosts.
func WithMaxIdleConnsPerHost ¶
func WithMaxIdleConnsPerHost(n int) BaseOption
WithMaxIdleConnsPerHost sets the maximum number of idle connections per host.
func WithReadBufferSize ¶
func WithReadBufferSize(size int) BaseOption
WithReadBufferSize sets the read buffer size for connections.
func WithResponseHeaderTimeout ¶
func WithResponseHeaderTimeout(d time.Duration) BaseOption
WithResponseHeaderTimeout sets the timeout for reading response headers.
func WithTLSConfig ¶
func WithTLSConfig(cfg *tls.Config) BaseOption
WithTLSConfig sets a custom TLS configuration.
func WithTLSHandshakeTimeout ¶
func WithTLSHandshakeTimeout(d time.Duration) BaseOption
WithTLSHandshakeTimeout sets the TLS handshake timeout.
func WithWriteBufferSize ¶
func WithWriteBufferSize(size int) BaseOption
WithWriteBufferSize sets the write buffer size for connections.
type BasicAuthProvider ¶
BasicAuthProvider adds HTTP Basic authentication.
func NewBasicAuthProvider ¶
func NewBasicAuthProvider(username, password string) *BasicAuthProvider
NewBasicAuthProvider creates a new basic auth provider.
type BearerTokenProvider ¶
type BearerTokenProvider struct {
RefreshFunc func() (string, error)
// contains filtered or unexported fields
}
BearerTokenProvider adds a Bearer token to requests.
func NewBearerTokenProvider ¶
func NewBearerTokenProvider(token string) *BearerTokenProvider
NewBearerTokenProvider creates a new bearer token provider.
func NewRefreshableBearerTokenProvider ¶
func NewRefreshableBearerTokenProvider(token string, refresh func() (string, error)) *BearerTokenProvider
NewRefreshableBearerTokenProvider creates a bearer token provider with a refresh callback. The application must call Refresh to invoke it, or SetToken to replace the token directly. Requests and HTTP 401 responses do not trigger either operation automatically.
func (*BearerTokenProvider) AddAuth ¶
func (p *BearerTokenProvider) AddAuth(req *http.Request) error
AddAuth implements AuthProvider.
func (*BearerTokenProvider) Refresh ¶
func (p *BearerTokenProvider) Refresh() error
Refresh calls the refresh function and updates the token.
func (*BearerTokenProvider) SetToken ¶
func (p *BearerTokenProvider) SetToken(token string)
SetToken updates the token.
type BufferPool ¶
type BufferPool struct {
// contains filtered or unexported fields
}
BufferPool is a sync.Pool-based buffer pool for reducing allocations.
func DefaultBufferPool ¶
func DefaultBufferPool() *BufferPool
DefaultBufferPool returns the package's shared default BufferPool. The returned pool is the singleton — callers MUST treat it as read-only. Consumers that need to mutate (drain, replace) should construct their own via NewBufferPool.
func NewBufferPool ¶
func NewBufferPool(size int) (*BufferPool, error)
NewBufferPool creates a buffer pool whose buffers start with size bytes of capacity; size must be >= 0.
func (*BufferPool) Get ¶
func (p *BufferPool) Get() *bytes.Buffer
Get retrieves a buffer from the pool. The buffer is reset and ready for use.
func (*BufferPool) Put ¶
func (p *BufferPool) Put(b *bytes.Buffer)
Put returns a buffer to the pool. Buffers that have grown significantly larger than the initial size are discarded to avoid holding excessive memory.
func (*BufferPool) Size ¶
func (p *BufferPool) Size() int
Size returns the initial buffer size for this pool.
type CacheOption ¶
type CacheOption func(*CacheTransport)
CacheOption configures a CacheTransport.
func WithCacheHook ¶
func WithCacheHook(hook MetricsHook) CacheOption
WithCacheHook sets the metrics hook for hits and misses.
func WithCacheIdentityHeaders ¶
func WithCacheIdentityHeaders(names ...string) CacheOption
WithCacheIdentityHeaders adds request headers that identify the caller (for example X-API-Key) to the partition key, alongside Authorization and Cookie. Other identity headers are not detected automatically.
func WithMaxCacheBodyBytes ¶
func WithMaxCacheBodyBytes(n int64) CacheOption
WithMaxCacheBodyBytes caps the size of a stored body; larger responses pass through unstored. Default DefaultMaxCacheBodyBytes.
func WithMaxRetention ¶
func WithMaxRetention(d time.Duration) CacheOption
WithMaxRetention caps how long any response is kept, including responses kept only for revalidation. Default DefaultMaxRetention.
func WithRevalidation ¶
func WithRevalidation(timeout time.Duration, concurrency int) CacheOption
WithRevalidation sets the timeout and the concurrency cap for background (stale-while-revalidate) revalidations. Defaults DefaultRevalidateTimeout and DefaultMaxConcurrentRevalidates.
func WithStaleIfError ¶
func WithStaleIfError(d time.Duration) CacheOption
WithStaleIfError lets the cache serve a stale response for up to d when revalidation returns an inner transport error (including local admission refusal) or 5xx, unless the response says must-revalidate or no-cache. Caller cancellation and expired caller deadlines remain errors. A response's own stale-if-error directive also grants permission.
func WithStaleWhileRevalidate ¶
func WithStaleWhileRevalidate(d time.Duration) CacheOption
WithStaleWhileRevalidate lets the cache serve a stale response for up to d while it revalidates in the background, unless the response says must-revalidate or no-cache. A response's own stale-while-revalidate directive also grants permission.
type CacheStore ¶
type CacheStore interface {
Get(key string) (*CachedResponse, bool)
Set(key string, value *CachedResponse, ttl time.Duration)
Delete(key string)
}
CacheStore is the storage behind CacheTransport. Implementations must be safe for concurrent use and must treat stored values as immutable. ttl > 0 bounds how long an entry may be returned; ttl <= 0 means no expiry.
type CacheTransport ¶
type CacheTransport struct {
// contains filtered or unexported fields
}
CacheTransport is a private HTTP cache (RFC 9111) for GET requests.
Stored responses are keyed by the effective request target — the URL with the request's Host as its authority — and partitioned by caller identity — the Authorization and Cookie headers plus any WithCacheIdentityHeaders. Callers must configure every additional identity header (including API-key headers) and use separate stores for identities hidden in a transport. These keys do not establish application authorization or tenant boundaries. Within a partition the cache honours Vary, corrected Age, the request directives no-store, no-cache, max-age, min-fresh, max-stale and only-if-cached, and the response directives no-store, no-cache, must-revalidate, max-age and Expires. A response without explicit freshness is stored only when it has a validator, and is revalidated on every use. Range, HEAD, caller-conditional and body-bearing requests bypass the cache; unsafe methods with a response below 400 invalidate the target URI within that request's partition, and a fetch or revalidation still in flight when they do never stores what it read.
func NewCacheTransport ¶
func NewCacheTransport(base http.RoundTripper, store CacheStore, opts ...CacheOption) (*CacheTransport, error)
NewCacheTransport creates a cache transport over store; a nil store uses a default NewMemoryCache.
func (*CacheTransport) Close ¶
func (t *CacheTransport) Close() error
Close stops background revalidations and waits for them to finish.
func (*CacheTransport) CloseIdleConnections ¶
func (t *CacheTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*CacheTransport) Unwrap ¶
func (t *CacheTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type CachedResponse ¶
type CachedResponse struct {
StatusCode int
Header http.Header
Body []byte
RequestTime time.Time // when the request that produced it was sent
ResponseTime time.Time // when it was received
VaryHeaders http.Header // request header values named by the response's Vary
}
CachedResponse is a response held by CacheTransport. Freshness is derived from Header (Cache-Control, Expires, Date, Age) and the request and response times (RFC 9111 §4.2).
type Chain ¶
type Chain []TransportFunc
Chain composes RoundTripper decorators around a base transport. Build returns an http.RoundTripper for use with an ordinary http.Client.
Example:
transport, err := httpx.NewChain(
httpx.WithCompressionT(),
httpx.WithCircuitBreakerT(),
httpx.WithRetryT(httpx.WithMaxAttempts(3)),
).Build(nil)
func APIClientChain ¶
func APIClientChain() Chain
APIClientChain returns a chain for REST API clients: retry inside the cache, so a hit is never retried and a miss is.
func DefaultChain ¶
func DefaultChain() Chain
DefaultChain returns compression, a circuit breaker and retry, in the NewClient order: the breaker is inside retry, so it counts every attempt.
func NewChain ¶
func NewChain(funcs ...TransportFunc) Chain
NewChain creates a new transport chain. Transports are applied in order: first added is innermost (closest to base). Order is semantics, not style: a layer sees what the layers outside it send and counts what the layers inside it return. A circuit breaker inside retry counts every attempt, outside it only logical outcomes; a limiter or rate limit inside retry and hedging budgets every network attempt, outside them one logical call; a cache outside the breaker and the budgets serves hits without them, inside them not at all while the breaker is open; and a cache outside the auth layer would partition before the credential is set. NewClient's order (compression, circuit breaker, limiter, rate limit, retry, hedging, cache, auth, metrics, logging) is the one to start from.
func ResilientChain ¶
func ResilientChain() Chain
ResilientChain returns a chain optimized for reliability, in NewClient's order: every attempt passes the breaker and holds a limiter slot, and the cache answers — stale if need be — even while the breaker is open.
func (Chain) Append ¶
func (c Chain) Append(funcs ...TransportFunc) Chain
Append adds transport functions to the chain. Returns a new chain without modifying the original.
func (Chain) Build ¶
func (c Chain) Build(base http.RoundTripper) (http.RoundTripper, error)
Build applies all transport functions to the base transport. If base is nil, a default NewBaseTransport is used.
func (Chain) Client ¶
Client creates an http.Client with the transport chain. If base is nil, a default NewBaseTransport is used. A negative timeout is rejected; zero disables the client timeout.
func (Chain) Prepend ¶
func (c Chain) Prepend(funcs ...TransportFunc) Chain
Prepend adds transport functions to the beginning of the chain. Returns a new chain without modifying the original.
type ChainAuthProvider ¶
type ChainAuthProvider struct {
Providers []AuthProvider
}
ChainAuthProvider chains multiple auth providers.
func NewChainAuthProvider ¶
func NewChainAuthProvider(providers ...AuthProvider) *ChainAuthProvider
NewChainAuthProvider creates a new chain of auth providers.
type CircuitOption ¶
type CircuitOption func(*CircuitTransport)
CircuitOption configures a CircuitTransport.
func WithFailureThreshold ¶
func WithFailureThreshold(n int) CircuitOption
WithFailureThreshold sets how many consecutive failures open an origin's circuit. n must be within [1, math.MaxUint32].
func WithIsFailure ¶
func WithIsFailure(fn func(*http.Response, error) bool) CircuitOption
WithIsFailure sets how a response or transport error is classified.
func WithMaxBreakers ¶
func WithMaxBreakers(n int) CircuitOption
WithMaxBreakers caps how many origins keep a breaker. The least recently used origin beyond the cap loses its breaker and starts again closed; a request already admitted by the dropped breaker still completes, so the cap bounds the origins retained, not the requests in flight.
func WithOnStateChange ¶
func WithOnStateChange(fn func(origin Origin, from, to State)) CircuitOption
WithOnStateChange sets a callback for an origin's state transitions, including Reset and eviction of a breaker that was not closed (both report a transition to closed). It runs synchronously, serialized with breaker state changes, so it must be quick and must not call back into the transport.
func WithOpenTimeout ¶
func WithOpenTimeout(d time.Duration) CircuitOption
WithOpenTimeout sets how long a circuit stays open before admitting probes.
func WithSuccessThreshold ¶
func WithSuccessThreshold(n int) CircuitOption
WithSuccessThreshold sets how many probes a half-open circuit admits and how many consecutive successes close it. n must be within [1, math.MaxUint32].
type CircuitTransport ¶
type CircuitTransport struct {
// contains filtered or unexported fields
}
CircuitTransport fails fast when an origin (scheme, host and port) is unhealthy. Each origin has its own breaker: consecutive failures open it, after the open timeout it admits up to the success threshold of probe requests, and that many consecutive successes close it again; any probe failure reopens it. A request cancelled by its caller counts as neither success nor failure, and an outcome that completes after its breaker changed state is ignored. A rejected request fails with ErrCircuitOpen, both while open and beyond the probe count while half-open. At most DefaultMaxOrigins breakers are kept (WithMaxBreakers); the least recently used origin is dropped beyond that and starts closed on its next request.
func NewCircuitTransport ¶
func NewCircuitTransport(base http.RoundTripper, opts ...CircuitOption) (*CircuitTransport, error)
NewCircuitTransport creates a per-origin circuit breaker transport. Defaults: DefaultFailureThreshold, DefaultSuccessThreshold, DefaultOpenTimeout, DefaultMaxOrigins breakers; any error, nil response or 5xx from the wrapped transport is a failure, except caller cancellation. Deadline errors count as failures. Put local admission layers outside the breaker to keep their refusals out of these outcomes.
func (*CircuitTransport) CloseIdleConnections ¶
func (t *CircuitTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*CircuitTransport) Reset ¶
func (t *CircuitTransport) Reset(origin Origin)
Reset gives origin a fresh, closed breaker.
func (*CircuitTransport) State ¶
func (t *CircuitTransport) State(origin Origin) State
State returns origin's circuit state; an origin with no breaker is closed.
func (*CircuitTransport) Unwrap ¶
func (t *CircuitTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type Codec ¶
type Codec interface {
ContentType() string
Encode(v any) ([]byte, error)
Decode(data []byte, v any) error
}
Codec handles encoding/decoding for a content type.
func RegisteredCodecs ¶
func RegisteredCodecs() []Codec
RegisteredCodecs returns the registered codecs sorted by content type, so the Accept header built from them is the same on every request.
type CompressionOption ¶
type CompressionOption func(*CompressionTransport)
CompressionOption configures a CompressionTransport.
func WithBrotliLevel ¶
func WithBrotliLevel(level int) CompressionOption
WithBrotliLevel sets the brotli compression level (0-11). Requires brotli to be registered via import _ "github.com/ashtonian/pkg/httpx/compress/brotli"
func WithCompressionPool ¶
func WithCompressionPool(pool *BufferPool) CompressionOption
WithCompressionPool sets the buffer pool.
func WithCompressor ¶
func WithCompressor(encoding string, c Compressor) CompressionOption
WithCompressor registers a custom compressor for an encoding. This can also be used to override built-in compressors.
func WithDeflateLevel ¶
func WithDeflateLevel(level int) CompressionOption
WithDeflateLevel sets the deflate compression level: flate.HuffmanOnly (-2), flate.DefaultCompression (-1), or 0 through 9.
func WithEncodings ¶
func WithEncodings(encodings ...string) CompressionOption
WithEncodings sets the advertised encoding list without quality weights. Each encoding needs a registered compressor or an earlier WithCompressor option; an unavailable encoding makes construction fail.
func WithGzipLevel ¶
func WithGzipLevel(level int) CompressionOption
WithGzipLevel sets the gzip compression level: gzip.HuffmanOnly (-2), gzip.DefaultCompression (-1), or 0 through 9.
type CompressionTransport ¶
type CompressionTransport struct {
Pool *BufferPool
Encodings []string // Priority order for Accept-Encoding
// contains filtered or unexported fields
}
CompressionTransport negotiates response content encodings and lazily decompresses supported complete responses. It does not compress outgoing request bodies; callers can use Compress explicitly for that purpose.
func NewCompressionTransport ¶
func NewCompressionTransport(base http.RoundTripper, opts ...CompressionOption) (*CompressionTransport, error)
NewCompressionTransport creates a new compression transport.
By default, it advertises registered brotli, gzip and deflate encodings, in that order without quality weights. The server chooses the encoding. Select other registered encodings with WithEncodings or add an implementation with WithCompressor. The transport automatically decompresses complete response bodies. Partial representations retain their encoding and byte offsets; Range and HEAD requests do not receive an automatic Accept-Encoding header.
To enable brotli support, import the compress/brotli submodule:
import _ "github.com/ashtonian/pkg/httpx/compress/brotli"
func (*CompressionTransport) CloseIdleConnections ¶
func (t *CompressionTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*CompressionTransport) Compress ¶
func (t *CompressionTransport) Compress(data []byte, encoding string) ([]byte, error)
Compress compresses data using the specified encoding.
func (*CompressionTransport) Unwrap ¶
func (t *CompressionTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type Compressor ¶
type Compressor interface {
// Compress compresses data, using the provided buffer for output.
// Returns the compressed bytes (may be a slice of buf's backing array).
Compress(data []byte, buf *bytes.Buffer) ([]byte, error)
// Decompress wraps a reader with decompression.
Decompress(r io.Reader) (io.Reader, error)
}
Compressor handles compression and decompression for a specific encoding. Implement this interface to add custom compression algorithms.
func GetCompressor ¶
func GetCompressor(encoding string) (Compressor, bool)
GetCompressor returns a new compressor instance for the encoding, if registered.
type CountingHook ¶
type CountingHook struct {
Requests atomic.Int64
Responses atomic.Int64
Errors atomic.Int64
Retries atomic.Int64
CacheHits atomic.Int64
CacheMisses atomic.Int64
}
CountingHook is a simple MetricsHook that counts events. All fields are safe for concurrent use.
func (*CountingHook) OnCacheHit ¶
func (h *CountingHook) OnCacheHit(_ *http.Request, _ bool)
func (*CountingHook) OnCacheMiss ¶
func (h *CountingHook) OnCacheMiss(_ *http.Request)
func (*CountingHook) OnRequest ¶
func (h *CountingHook) OnRequest(*http.Request)
func (*CountingHook) OnResponse ¶
type DecodeOption ¶
type DecodeOption func(*decodeConfig)
DecodeOption configures the decoding helpers (Get, Post, Put, Patch, Do and DecodeResponse).
func WithMaxResponseBytes ¶
func WithMaxResponseBytes(n int64) DecodeOption
WithMaxResponseBytes caps the response body a helper reads before decoding. A larger body fails with ErrResponseTooLarge instead of being decoded from a prefix. Default DefaultMaxResponseBytes.
type FuncAuthProvider ¶
FuncAuthProvider wraps a function as an AuthProvider.
type HedgingOption ¶
type HedgingOption func(*HedgingTransport)
HedgingOption configures a HedgingTransport.
func WithHedgeIf ¶
func WithHedgeIf(fn func(*http.Request) bool) HedgingOption
WithHedgeIf sets a function to determine whether to hedge a request.
func WithMaxHedgedRequests ¶
func WithMaxHedgedRequests(n int) HedgingOption
WithMaxHedgedRequests sets the maximum number of concurrent requests.
type HedgingTransport ¶
type HedgingTransport struct {
// contains filtered or unexported fields
}
HedgingTransport implements request hedging for tail latency reduction.
func NewHedgingTransport ¶
func NewHedgingTransport(base http.RoundTripper, delay time.Duration, opts ...HedgingOption) (*HedgingTransport, error)
NewHedgingTransport creates a new hedging transport.
delay is the time to wait before sending a hedge request. By default, up to 2 concurrent requests are allowed.
func (*HedgingTransport) CloseIdleConnections ¶
func (t *HedgingTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*HedgingTransport) RoundTrip ¶
RoundTrip implements http.RoundTripper.
Each attempt runs under its own cancellable context. The first attempt to return a response wins: every other attempt is cancelled and its response, if one still arrives, is drained and closed. The winner's context stays alive until the caller finishes with its body, so a delayed or streaming body stays readable.
func (*HedgingTransport) Unwrap ¶
func (t *HedgingTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type LatencyHook ¶
type LatencyHook struct {
// contains filtered or unexported fields
}
LatencyHook records request latencies: running aggregates (count, sum, min, max) over every response since creation or Reset, and the most recent window of samples. Memory is bounded by the window. All methods are safe for concurrent use.
func NewLatencyHook ¶
func NewLatencyHook(window int) (*LatencyHook, error)
NewLatencyHook creates a LatencyHook keeping the last window samples.
func (*LatencyHook) Avg ¶
func (h *LatencyHook) Avg() time.Duration
Avg returns the mean of all recorded latencies.
func (*LatencyHook) Count ¶
func (h *LatencyHook) Count() int64
Count returns how many latencies were recorded.
func (*LatencyHook) Max ¶
func (h *LatencyHook) Max() time.Duration
Max returns the largest recorded latency.
func (*LatencyHook) Min ¶
func (h *LatencyHook) Min() time.Duration
Min returns the smallest recorded latency.
func (*LatencyHook) OnCacheHit ¶
func (h *LatencyHook) OnCacheHit(*http.Request, bool)
func (*LatencyHook) OnCacheMiss ¶
func (h *LatencyHook) OnCacheMiss(*http.Request)
func (*LatencyHook) OnRequest ¶
func (h *LatencyHook) OnRequest(*http.Request)
func (*LatencyHook) OnResponse ¶
func (*LatencyHook) Recent ¶
func (h *LatencyHook) Recent() []time.Duration
Recent returns the samples in the window, oldest first.
func (*LatencyHook) Reset ¶
func (h *LatencyHook) Reset()
Reset clears the aggregates and the window.
func (*LatencyHook) Sum ¶
func (h *LatencyHook) Sum() time.Duration
Sum returns the total of all recorded latencies.
type LimiterOption ¶
type LimiterOption func(*LimiterTransport)
LimiterOption configures a LimiterTransport.
func WithAcquireTimeout ¶
func WithAcquireTimeout(d time.Duration) LimiterOption
WithAcquireTimeout sets the timeout for acquiring a slot. Default is 0 (wait until a slot is available or the request context ends).
func WithOnBlocked ¶
func WithOnBlocked(fn func()) LimiterOption
WithOnBlocked sets a callback for when a request blocks waiting for a slot.
type LimiterTransport ¶
type LimiterTransport struct {
// contains filtered or unexported fields
}
LimiterTransport limits concurrent in-flight requests. A request holds its slot from before it is sent until its response body is read to the end or closed; callers must close response bodies to free their slot.
func NewLimiterTransport ¶
func NewLimiterTransport(base http.RoundTripper, maxConcurrent int, opts ...LimiterOption) (*LimiterTransport, error)
NewLimiterTransport creates a new concurrency limiter transport.
func (*LimiterTransport) Available ¶
func (t *LimiterTransport) Available() int
Available returns the number of available slots.
func (*LimiterTransport) Capacity ¶
func (t *LimiterTransport) Capacity() int
Capacity returns the maximum number of concurrent requests.
func (*LimiterTransport) CloseIdleConnections ¶
func (t *LimiterTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*LimiterTransport) InFlight ¶
func (t *LimiterTransport) InFlight() int
InFlight returns the number of in-flight requests.
func (*LimiterTransport) Unwrap ¶
func (t *LimiterTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type LogEntry ¶
type LogEntry struct {
Type string `json:"type"` // "request" or "response"
Method string `json:"method,omitempty"`
URL string `json:"url,omitempty"`
StatusCode int `json:"status_code,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
ContentType string `json:"content_type,omitempty"`
Error string `json:"error,omitempty"`
}
LogEntry represents a structured log entry.
type LoggingHook ¶
type LoggingHook interface {
LogRequest(req *http.Request)
LogResponse(req *http.Request, resp *http.Response, duration time.Duration, err error)
}
LoggingHook receives logging events from a LoggingTransport. Both methods receive redacted snapshots without bodies (see LoggingTransport); resp is nil and err non-nil when the request failed.
type LoggingOption ¶
type LoggingOption func(*LoggingTransport)
LoggingOption configures a LoggingTransport.
func WithSensitiveHeaders ¶
func WithSensitiveHeaders(names ...string) LoggingOption
WithSensitiveHeaders redacts the named headers in addition to the defaults. Names are matched case-insensitively.
func WithSensitiveQueryParams ¶
func WithSensitiveQueryParams(names ...string) LoggingOption
WithSensitiveQueryParams redacts the named query parameters in addition to the defaults. Names are matched case-insensitively.
type LoggingTransport ¶
type LoggingTransport struct {
// contains filtered or unexported fields
}
LoggingTransport reports each request and response to a LoggingHook.
The hook never sees the live request or response: it receives detached snapshots built from an allowlist of fields — method, URL, protocol, header, host, length and transfer coding, and the request context — with no body, no redirect response and no TLS state. Sensitive header values and credential query parameters are replaced with Redacted; URL userinfo and fragments are removed, from the request URL and from URL-valued headers (Referer, Location, Content-Location) alike; and an error is reported with every such URL in its text redacted. The hook's error is detached from the original cause, which only the caller receives. Redaction is always on; WithSensitiveHeaders and WithSensitiveQueryParams extend the defaults.
The guarantee covers what this transport hands its LoggingHook. Hooks of other transports — MetricsHook, RetryHook, the cache's hook — receive the live request, because they act on it rather than record it; do not log from them.
func NewLoggingTransport ¶
func NewLoggingTransport(base http.RoundTripper, hook LoggingHook, opts ...LoggingOption) (*LoggingTransport, error)
NewLoggingTransport creates a new logging transport. A nil hook logs nothing.
func (*LoggingTransport) CloseIdleConnections ¶
func (t *LoggingTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*LoggingTransport) Unwrap ¶
func (t *LoggingTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type MemoryCache ¶
type MemoryCache struct {
// contains filtered or unexported fields
}
MemoryCache is a bounded in-memory CacheStore: it keeps at most maxEntries responses and maxBytes of stored bodies and headers, evicting the least recently used entry first, and drops entries whose TTL has passed.
func NewMemoryCache ¶
func NewMemoryCache(opts ...MemoryCacheOption) (*MemoryCache, error)
NewMemoryCache creates a bounded in-memory cache. Defaults: DefaultMemoryCacheMaxEntries entries, DefaultMemoryCacheMaxBytes bytes.
func (*MemoryCache) Bytes ¶
func (c *MemoryCache) Bytes() int64
Bytes returns the accounted size of stored responses.
func (*MemoryCache) Get ¶
func (c *MemoryCache) Get(key string) (*CachedResponse, bool)
Get returns the stored response for key, if it has not expired.
func (*MemoryCache) Len ¶
func (c *MemoryCache) Len() int
Len returns the number of stored responses.
func (*MemoryCache) Set ¶
func (c *MemoryCache) Set(key string, value *CachedResponse, ttl time.Duration)
Set stores value under key for ttl; ttl <= 0 means no expiry (the entry still leaves on eviction). Stored values must not be modified afterwards.
type MemoryCacheOption ¶
type MemoryCacheOption func(*MemoryCache)
MemoryCacheOption configures a MemoryCache.
func WithMaxBytes ¶
func WithMaxBytes(n int64) MemoryCacheOption
WithMaxBytes caps the total size of stored bodies and headers. A single response larger than the cap is not stored.
func WithMaxEntries ¶
func WithMaxEntries(n int) MemoryCacheOption
WithMaxEntries caps the number of stored responses.
type MetricsHook ¶
type MetricsHook interface {
OnRequest(req *http.Request)
OnResponse(req *http.Request, resp *http.Response, duration time.Duration, err error)
OnRetry(req *http.Request, attempt int, err error)
OnCacheHit(req *http.Request, fresh bool)
OnCacheMiss(req *http.Request)
}
MetricsHook receives transport events for observability.
type MetricsTransport ¶
type MetricsTransport struct {
// contains filtered or unexported fields
}
MetricsTransport reports each request and its response or error to a MetricsHook.
func NewMetricsTransport ¶
func NewMetricsTransport(base http.RoundTripper, hook MetricsHook) (*MetricsTransport, error)
NewMetricsTransport creates a new metrics transport.
func (*MetricsTransport) CloseIdleConnections ¶
func (t *MetricsTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*MetricsTransport) Unwrap ¶
func (t *MetricsTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type MultiHook ¶
type MultiHook struct {
// contains filtered or unexported fields
}
MultiHook fans every event out to several MetricsHooks, including OnRetryCause for those that implement RetryCauseHook.
func NewMultiHook ¶
func NewMultiHook(hooks ...MetricsHook) *MultiHook
NewMultiHook combines hooks; nil hooks are skipped.
func (*MultiHook) OnCacheMiss ¶
func (*MultiHook) OnResponse ¶
func (*MultiHook) OnRetryCause ¶
OnRetryCause forwards to the hooks that implement RetryCauseHook.
type Option ¶
type Option func(*clientConfig)
Option configures a client.
func WithAuth ¶
func WithAuth(originURL string, provider AuthProvider) Option
WithAuth binds provider to the origin (scheme, host and port) of originURL; any path is ignored. Credentials are added only to requests for that origin — never to another host, port or scheme, including redirect hops the client follows. Repeat WithAuth to bind further origins.
func WithBaseTransport ¶
func WithBaseTransport(opts ...BaseOption) Option
WithBaseTransport configures the base http.Transport.
func WithCache ¶
func WithCache(store CacheStore, opts ...CacheOption) Option
WithCache enables the RFC 9111 private cache (see CacheTransport). A nil store uses a default NewMemoryCache.
func WithCircuitBreaker ¶
func WithCircuitBreaker(opts ...CircuitOption) Option
WithCircuitBreaker enables circuit breaker.
func WithCompression ¶
func WithCompression(opts ...CompressionOption) Option
WithCompression enables response compression negotiation and lazy decoding. It does not compress request bodies.
func WithHedging ¶
func WithHedging(delay time.Duration, opts ...HedgingOption) Option
WithHedging enables request hedging.
func WithLimiter ¶
func WithLimiter(maxConcurrent int, opts ...LimiterOption) Option
WithLimiter enables concurrency limiting.
func WithLogging ¶
func WithLogging(hook LoggingHook, opts ...LoggingOption) Option
WithLogging enables request/response logging.
func WithMetrics ¶
func WithMetrics(hook MetricsHook) Option
WithMetrics enables metrics collection.
func WithRateLimit ¶
func WithRateLimit(rps float64, burst int, opts ...RateLimitOption) Option
WithRateLimit enables rate limiting.
func WithRetry ¶
func WithRetry(opts ...RetryOption) Option
WithRetry enables retry with exponential backoff.
func WithTimeout ¶
WithTimeout sets the overall client timeout (applied to the whole request including body read). Pass 0 to disable; default is DefaultTimeout.
func WithTransport ¶
func WithTransport(t http.RoundTripper) Option
WithTransport sets a custom base transport. The configured base transport options (WithBaseTransport) are ignored when this is set.
type Origin ¶
type Origin struct {
// contains filtered or unexported fields
}
Origin is the scheme, host and port of a URL (RFC 6454): the boundary a credential is bound to. https://api.example.com and http://api.example.com are different origins, as are two ports on one host. The zero Origin matches no request.
func OriginOf ¶
OriginOf returns the origin of u, or the zero Origin when u is nil, not http(s), or has no host.
func ParseOrigin ¶
ParseOrigin returns the origin of an absolute http or https URL. Any path, query or fragment is ignored; userinfo is rejected so a credential cannot hide in a binding. Errors never repeat the input, which may hold a credential: a rejected URL is described by its scheme and host at most.
type QueryParamAuthProvider ¶
type QueryParamAuthProvider struct {
Key string // Query parameter name
Value string // Query parameter value
}
QueryParamAuthProvider adds authentication as a query parameter.
func NewQueryParamAuthProvider ¶
func NewQueryParamAuthProvider(key, value string) *QueryParamAuthProvider
NewQueryParamAuthProvider creates a new query parameter auth provider.
type RateLimitOption ¶
type RateLimitOption func(*RateLimitTransport)
RateLimitOption configures a RateLimitTransport.
func WithMaxBuckets ¶
func WithMaxBuckets(n int) RateLimitOption
WithMaxBuckets caps how many origins keep a token bucket.
func WithWait ¶
func WithWait() RateLimitOption
WithWait makes a request over the limit wait for a token instead of failing. The wait honours the request context; a wait that would outlast the context's deadline fails with ErrRateLimited at once.
type RateLimitTransport ¶
type RateLimitTransport struct {
// contains filtered or unexported fields
}
RateLimitTransport throttles requests with one token bucket per origin (scheme, host and port): each origin may send rps requests per second with bursts up to burst. At most DefaultMaxOrigins buckets are kept (WithMaxBuckets); the least recently used origin is dropped beyond that and starts with a full bucket on its next request. A request over the limit fails with ErrRateLimited, or waits for a token under WithWait.
func NewRateLimitTransport ¶
func NewRateLimitTransport(base http.RoundTripper, rps float64, burst int, opts ...RateLimitOption) (*RateLimitTransport, error)
NewRateLimitTransport creates a per-origin rate limiting transport.
func (*RateLimitTransport) CloseIdleConnections ¶
func (t *RateLimitTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*RateLimitTransport) Unwrap ¶
func (t *RateLimitTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type RetryCause ¶
type RetryCause string
RetryCause groups retries into status, network, timeout or unknown causes. The status category combines HTTP 429, 502, 503 and 504; it does not distinguish rate-limit responses from server failures.
const ( // RetryCauseStatus — server returned a retryable HTTP status // (502/503/504/429). RetryCauseStatus RetryCause = "status" // RetryCauseNetwork — network-level error (connection reset, // connection refused, broken pipe, EOF). RetryCauseNetwork RetryCause = "network" // RetryCauseTimeout — net.Error.Timeout() was true. RetryCauseTimeout RetryCause = "timeout" // RetryCauseUnknown — retryIf returned true but the cause didn't // match any of the above. Caller's custom retry condition. RetryCauseUnknown RetryCause = "unknown" )
RetryCause values.
type RetryCauseHook ¶
type RetryCauseHook interface {
OnRetryCause(req *http.Request, attempt int, cause RetryCause, err error)
}
RetryCauseHook is an OPTIONAL extension to MetricsHook. RetryTransport type-asserts the hook and calls OnRetryCause in addition to OnRetry when the assertion succeeds. Implementations that don't care about per-cause labelling don't need to implement it.
Splitting the cause from the legacy OnRetry signature avoids breaking every existing MetricsHook implementation while still letting modern observability stacks emit labelled counters.
type RetryOption ¶
type RetryOption func(*RetryTransport)
RetryOption configures a RetryTransport.
func WithBackoff ¶
func WithBackoff(initial, max time.Duration, multiplier float64) RetryOption
WithBackoff sets the backoff parameters. max also bounds a server's Retry-After: a response asking for a longer pause is returned to the caller instead of retried.
func WithJitter ¶
func WithJitter(jitter float64) RetryOption
WithJitter sets the jitter factor (0.0-1.0).
func WithMaxAttempts ¶
func WithMaxAttempts(n int) RetryOption
WithMaxAttempts sets the maximum number of attempts.
func WithMaxReplayBytes ¶
func WithMaxReplayBytes(n int64) RetryOption
WithMaxReplayBytes caps how much of a request body without GetBody is recorded, as the first attempt sends it, for replay. A larger body is sent once.
func WithRetryHook ¶
func WithRetryHook(hook MetricsHook) RetryOption
WithRetryHook sets the metrics hook for retry events.
func WithRetryIf ¶
func WithRetryIf(fn func(*http.Response, error) bool) RetryOption
WithRetryIf sets a custom retry condition.
func WithRetryNonIdempotent ¶
func WithRetryNonIdempotent() RetryOption
WithRetryNonIdempotent also replays non-idempotent requests (POST, PATCH, ...) that carry no Idempotency-Key. Use it only when the server deduplicates repeated requests; otherwise an ambiguous failure can execute the operation more than once.
func WithRetryOn ¶
func WithRetryOn(codes ...int) RetryOption
WithRetryOn sets the status codes that trigger a retry.
type RetryTransport ¶
type RetryTransport struct {
// contains filtered or unexported fields
}
RetryTransport implements exponential backoff with jitter.
A request is eligible for replay when its method is idempotent (RFC 9110 §9.2.2: GET, HEAD, OPTIONS, TRACE, PUT, DELETE), it carries an Idempotency-Key header, or the transport was built with WithRetryNonIdempotent. The application must ensure the server makes replay safe; this transport cannot deduplicate writes. Retried attempts clone the request metadata, but still consume and close request bodies.
func NewRetryTransport ¶
func NewRetryTransport(base http.RoundTripper, opts ...RetryOption) (*RetryTransport, error)
NewRetryTransport creates a new retry transport.
Defaults: 3 attempts, 100ms initial wait, 10s max wait, 2x multiplier, 10% jitter, 1 MiB recording bound for bodies without GetBody. Retries on 502, 503, 504, 429, connection reset/refused/aborted, broken pipe, EOF and network timeouts; caller cancellation and deadline errors are excluded.
func (*RetryTransport) CloseIdleConnections ¶
func (t *RetryTransport) CloseIdleConnections()
CloseIdleConnections forwards to the wrapped transport.
func (*RetryTransport) Unwrap ¶
func (t *RetryTransport) Unwrap() http.RoundTripper
Unwrap returns the wrapped transport.
type StructuredLoggingHook ¶
type StructuredLoggingHook struct {
LogFunc func(entry LogEntry)
}
StructuredLoggingHook is a LoggingHook that captures structured data.
func (*StructuredLoggingHook) LogRequest ¶
func (h *StructuredLoggingHook) LogRequest(req *http.Request)
LogRequest implements LoggingHook.
func (*StructuredLoggingHook) LogResponse ¶
func (h *StructuredLoggingHook) LogResponse(req *http.Request, resp *http.Response, duration time.Duration, err error)
LogResponse implements LoggingHook.
type TransportFunc ¶
type TransportFunc func(http.RoundTripper) (http.RoundTripper, error)
TransportFunc wraps a transport, returning an error when its configuration is invalid. This is the building block for the Chain API.
func WithAuthT ¶
func WithAuthT(originURL string, provider AuthProvider) TransportFunc
WithAuthT returns a TransportFunc that binds provider to the origin of originURL (see WithAuth).
func WithCacheT ¶
func WithCacheT(store CacheStore, opts ...CacheOption) TransportFunc
WithCacheT returns a TransportFunc that adds caching.
func WithCircuitBreakerT ¶
func WithCircuitBreakerT(opts ...CircuitOption) TransportFunc
WithCircuitBreakerT returns a TransportFunc that adds circuit breaker.
func WithCompressionT ¶
func WithCompressionT(opts ...CompressionOption) TransportFunc
WithCompressionT returns a TransportFunc that adds compression.
func WithHedgingT ¶
func WithHedgingT(delay time.Duration, opts ...HedgingOption) TransportFunc
WithHedgingT returns a TransportFunc that adds request hedging.
func WithLimiterT ¶
func WithLimiterT(maxConcurrent int, opts ...LimiterOption) TransportFunc
WithLimiterT returns a TransportFunc that adds concurrency limiting.
func WithLoggingT ¶
func WithLoggingT(hook LoggingHook, opts ...LoggingOption) TransportFunc
WithLoggingT returns a TransportFunc that adds logging.
func WithMetricsT ¶
func WithMetricsT(hook MetricsHook) TransportFunc
WithMetricsT returns a TransportFunc that adds metrics.
func WithRateLimitT ¶
func WithRateLimitT(rps float64, burst int, opts ...RateLimitOption) TransportFunc
WithRateLimitT returns a TransportFunc that adds rate limiting.
func WithRetryT ¶
func WithRetryT(opts ...RetryOption) TransportFunc
WithRetryT returns a TransportFunc that adds retry with backoff.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
codec
|
|
|
msgpack
module
|
|
|
compress
|
|
|
brotli
module
|
|
|
examples
|
|
|
quickstart
command
Command quickstart is the README Quick Start: compose HTTP compression, retry/backoff, and a private validator-aware cache around an ordinary http.Client.
|
Command quickstart is the README Quick Start: compose HTTP compression, retry/backoff, and a private validator-aware cache around an ordinary http.Client. |
|
internal
|
|
|
testutil
Package testutil provides testing utilities for the httpx package.
|
Package testutil provides testing utilities for the httpx package. |