http

package
v1.53.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: Apache-2.0 Imports: 34 Imported by: 23

Documentation

Overview

Package http provides an enhanced HTTP client with built-in support for authentication, retries, tracing, and middleware.

The client supports multiple authentication methods (Basic, Digest, NTLM, OAuth, AWS Sigv4), automatic retries with exponential backoff, request/response tracing, and a flexible middleware system.

Basic Usage:

client := http.NewClient()
resp, err := client.R(context.Background()).GET("https://api.example.com/data")

With Authentication:

client := http.NewClient().
	Auth("username", "password").
	Digest(true)

With AWS Sigv4 Authentication:

cfg, _ := awsconfig.LoadDefaultConfig(ctx)
client := http.NewClient().AWSAuthSigV4(cfg).AWSService("s3")

With Retries and Timeout:

client := http.NewClient().
	Retry(3, time.Second, 2.0).
	Timeout(30 * time.Second)

With Request Tracing:

client := http.NewClient().
	Trace(http.TraceAll)  // Log full request/response details

The client can also be used as a standard http.RoundTripper:

httpClient := &http.Client{
	Transport: http.NewClient().Auth("user", "pass").RoundTripper(),
}

Index

Constants

View Source
const MaxBufferSizeProperty = "http.request.maxBufferSize"

MaxBufferSizeProperty caps how many bytes of an io.Reader request body are buffered for retry replay. Bodies larger than this stream through once and cannot be retried. Set -P http.request.maxBufferSize=0 to disable the cap.

Variables

View Source
var AuthStyleAutoDetect = middlewares.AuthStyleAutoDetect
View Source
var AuthStyleInHeader = middlewares.AuthStyleInHeader
View Source
var AuthStyleInParams = middlewares.AuthStyleInParams
View Source
var TraceAll = TraceConfig{
	MaxBodyLength:   4096,
	Body:            true,
	Response:        true,
	QueryParam:      true,
	FormParams:      true,
	Headers:         true,
	ResponseHeaders: true,
	TLS:             true,
	Auth:            true,
}
View Source
var TraceHeaders = TraceConfig{
	Body:            false,
	Response:        false,
	QueryParam:      true,
	FormParams:      true,
	Headers:         true,
	ResponseHeaders: true,
	TLS:             false,
	Auth:            true,
}

Functions

func Error added in v1.13.0

func Error(span trace.Span, err error) bool

func ToCurl added in v1.46.0

func ToCurl(req *http.Request) string

ToCurl converts an http.Request into an equivalent curl command string. All headers including Authorization are included unredacted so the command can be copy-pasted for debugging.

func WriteHARFile added in v1.52.0

func WriteHARFile(collector *har.Collector, path string) error

WriteHARFile serializes collector.Entries() into a HAR 1.2 file at path. Designed for use from a context.AfterFunc hook owned by the caller — commons/http does not register any lifecycle itself.

Types

type AuthConfig added in v1.13.0

type AuthConfig struct {
	// Username for basic Auth
	Username string

	// Password for basic Auth
	Password string

	// Use digest access authentication
	Digest bool

	// Ntlm controls whether to use NTLM
	Ntlm bool

	// Ntlmv2 controls whether to use NTLMv2
	Ntlmv2 bool

	// AWS Sigv4 authentication
	AWSCredentialsProvider aws.CredentialsProvider
	AWSRegion              string
	AWSService             string
	AWSEndpoint            string
}

func (*AuthConfig) IsEmpty added in v1.16.0

func (a *AuthConfig) IsEmpty() bool

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an enhanced HTTP client with built-in support for authentication, retries, tracing, and middleware. It provides a fluent API for configuring requests and can be used as a drop-in replacement for http.Client.

Example:

client := http.NewClient().
	Auth("user", "pass").
	Retry(3, time.Second, 2.0).
	Trace(http.TraceHeaders).
	Timeout(30 * time.Second)

resp, err := client.R(ctx).
	GET("https://api.example.com/data")

func NewClient

func NewClient() *Client

NewClient creates a new HTTP client with default settings. The client has a default timeout of 2 minutes and can be customized using the fluent API methods.

Example:

client := http.NewClient().
	BaseURL("https://api.example.com").
	Header("X-API-Key", "secret").
	InsecureSkipVerify(true)

func (*Client) AWSAuthSigV4 added in v1.45.0

func (c *Client) AWSAuthSigV4(cfgs ...aws.Config) *Client

AWSAuthSigV4 configures AWS Signature Version 4 authentication. With no arguments, it loads the default AWS config (env vars, ~/.aws, IAM role, etc.). Pass an aws.Config to use specific credentials/region.

Example with defaults:

client.AWSAuthSigV4()

Example with explicit config:

cfg, _ := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion("us-east-1"))
client.AWSAuthSigV4(cfg)

func (*Client) AWSEndpoint added in v1.45.0

func (c *Client) AWSEndpoint(endpoint string) *Client

AWSEndpoint sets a custom AWS endpoint (e.g., for LocalStack testing).

func (*Client) AWSService added in v1.45.0

func (c *Client) AWSService(service string) *Client

AWSService sets the AWS service name for SigV4 signing. If not set, the service is inferred from the request URL hostname.

func (*Client) Auth added in v1.13.0

func (c *Client) Auth(username, password string) *Client

Auth configures authentication credentials for the client. By default, this sets up HTTP Basic Authentication. Use Digest(), NTLM(), or NTLMV2() to switch authentication methods.

Example:

// Basic auth
client.Auth("username", "password")

// Digest auth
client.Auth("username", "password").Digest(true)

// NTLM auth with domain
client.Auth("DOMAIN\\username", "password").NTLM(true)

func (*Client) BaseURL added in v1.13.0

func (c *Client) BaseURL(url string) *Client

func (*Client) CacheDNS added in v1.13.0

func (c *Client) CacheDNS(val bool) *Client

func (*Client) ConnectTo added in v1.13.0

func (c *Client) ConnectTo(host string) *Client

ConnectTo overrides the target host:port for requests. This is useful for testing against specific IPs or when dealing with DNS issues. The original hostname is preserved in the Host header.

Example:

// Connect to a specific IP instead of using DNS
client.ConnectTo("192.168.1.100:8080")

// Test against localhost while preserving the original Host header
client.ConnectTo("localhost:3000")

func (*Client) CurlLog added in v1.46.0

func (c *Client) CurlLog() *Client

func (*Client) Digest added in v1.25.0

func (c *Client) Digest(val bool) *Client

func (*Client) DisableKeepAlive added in v1.13.0

func (c *Client) DisableKeepAlive(val bool) *Client

DisableKeepAlives prevents reuse of TCP connections

func (*Client) HAR added in v1.47.0

func (c *Client) HAR(handler func(*har.Entry)) *Client

HAR enables HAR capture with default config. handler is called with each request/response entry after the round-trip. HAR(nil) is a no-op.

func (*Client) HARCollector added in v1.47.0

func (c *Client) HARCollector(collector *har.Collector) *Client

HARCollector enables HAR capture using a Collector that accumulates all entries (including OAuth token fetches, redirect hops, and retry attempts).

func (*Client) HARWithConfig added in v1.47.0

func (c *Client) HARWithConfig(config har.HARConfig, handler func(*har.Entry)) *Client

HARWithConfig enables HAR capture with a custom HARConfig.

func (*Client) Header added in v1.13.0

func (c *Client) Header(key, val string) *Client

func (*Client) InsecureSkipVerify added in v1.13.0

func (c *Client) InsecureSkipVerify(val bool) *Client

InsecureSkipVerify disables TLS certificate verification. WARNING: This makes the client vulnerable to man-in-the-middle attacks. Only use in development or when connecting to services with self-signed certificates.

Example:

// Accept any certificate (dangerous!)
client.InsecureSkipVerify(true)

func (*Client) NTLM added in v1.13.0

func (c *Client) NTLM(val bool) *Client

func (*Client) NTLMV2 added in v1.13.0

func (c *Client) NTLMV2(val bool) *Client

func (*Client) OAuth added in v1.15.0

func (c *Client) OAuth(config middlewares.OauthConfig) *Client

OAuth configures OAuth 2.0 authentication for the client. Supports various OAuth flows including client credentials and authorization code.

Example:

client.OAuth(middlewares.OauthConfig{
	ClientID:     "client-id",
	ClientSecret: "client-secret",
	TokenURL:     "https://auth.example.com/token",
	Scopes:       []string{"read", "write"},
})

func (*Client) Proxy added in v1.13.0

func (c *Client) Proxy(url string) *Client

func (*Client) R added in v1.13.0

func (c *Client) R(ctx context.Context) *Request

R creates a new request with the given context. The request inherits all settings from the client (headers, auth, etc.) and can be further customized before execution.

Example:

resp, err := client.R(ctx).
	Header("X-Request-ID", "123").
	QueryParam("page", "1").
	GET("/users")

func (*Client) RedirectPolicy added in v1.47.0

func (c *Client) RedirectPolicy(maxRedirects int) *Client

RedirectPolicy controls redirect following. maxRedirects=0 disables redirect following entirely. Values >0 limit the number of redirects.

func (*Client) Retry added in v1.13.0

func (c *Client) Retry(maxRetries uint, baseDuration time.Duration, exponent float64) *Client

Retry configures automatic retry behavior with exponential backoff. Failed requests will be retried up to maxRetries times, with delays calculated as baseDuration * (exponent ^ attemptNumber).

Parameters:

  • maxRetries: Maximum number of retry attempts (0 disables retries)
  • baseDuration: Initial delay between retries
  • exponent: Multiplier for exponential backoff (typically 2.0)

Example:

// Retry up to 3 times with delays of 1s, 2s, 4s
client.Retry(3, time.Second, 2.0)

func (*Client) RetryStrategy added in v1.52.0

func (c *Client) RetryStrategy(fn RetryStrategy) *Client

RetryStrategy installs a callback that decides whether each HTTP attempt should be retried. When set, it fully supersedes the legacy Retry() exponential-backoff loop and owns the retry policy (including the attempt cap). See the RetryStrategy type and the RetryOnStatus helper.

Example — retry on 429 and 5xx, honoring Retry-After:

client := http.NewClient().RetryStrategy(
    http.RetryOnStatus(5, time.Second,
        429, 502, 503, 504),
)

func (*Client) RoundTrip added in v1.40.2

func (c *Client) RoundTrip(r *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

func (*Client) RoundTripper added in v1.40.2

func (c *Client) RoundTripper() http.RoundTripper

func (*Client) TLSConfig added in v1.22.2

func (c *Client) TLSConfig(conf TLSConfig) (*Client, error)

TLSConfig configures advanced TLS settings including custom CAs, client certificates, and handshake timeout.

Example:

client.TLSConfig(TLSConfig{
	CA:                 caPEM,        // Custom CA certificate
	Cert:               clientCert,   // Client certificate for mTLS
	Key:                clientKey,    // Client private key
	InsecureSkipVerify: false,        // Verify server certificate
	HandshakeTimeout:   10 * time.Second,
})

func (*Client) Timeout added in v1.13.0

func (c *Client) Timeout(d time.Duration) *Client

Timeout specifies a time limit for requests made by this Client.

Default: 2 minutes

func (*Client) Trace added in v1.15.0

func (c *Client) Trace(config TraceConfig) *Client

Trace enables request/response tracing with customizable detail levels. Traced information is added to the context and can be retrieved by middleware.

Use predefined configs for common scenarios:

  • TraceAll: Full details including headers, body, and TLS
  • TraceHeaders: Headers and query params only (no body)

Example:

client.Trace(http.TraceConfig{
	Headers:         true,
	ResponseHeaders: true,
	Body:            true,
	Response:        true,
	MaxBodyLength:   1024,  // Limit body size in traces
})

func (*Client) TraceToStdout added in v1.16.0

func (c *Client) TraceToStdout(config TraceConfig, verbose ...logger.Verbose) *Client

TraceToStdout installs the stdout trace middleware. Calling it a second time on the same Client merges the new config into the existing one instead of stacking a second middleware — this lets WithLogger (the -v ladder) and WithContext (-P http.log=) both contribute without doubling every traced request.

func (*Client) Use added in v1.13.0

func (c *Client) Use(middlewares ...middlewares.Middleware) *Client

Use adds middleware to the client's transport chain. Middleware functions wrap the underlying RoundTripper and can modify requests/responses, add logging, implement caching, etc.

Middleware is applied in the order it was added.

Example:

client.Use(func(rt http.RoundTripper) http.RoundTripper {
	return middlewares.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
		req.Header.Set("X-Custom", "value")
		return rt.RoundTrip(req)
	})
})

func (*Client) UserAgent added in v1.16.0

func (c *Client) UserAgent(agent string) *Client

func (*Client) WithContext added in v1.52.0

func (c *Client) WithContext(ctx CommonsHTTPContext, feature string) *Client

WithContext configures the client from a context-object's data accessors. The feature name lets implementations distinguish callers (e.g. "takealot" vs "xero") for per-feature property overrides.

Order of operations:

  1. WithLogger(ctx.GetLogger()) — installs the -v ladder trace.
  2. ctx.HTTPTraceConfig(feature) — if set, merges into the trace via TraceToStdout's dedupe path. Authorization is added to RedactedHeaders.
  3. ctx.HARFor(feature) — if a collector is returned, attaches it either as a full-body capture (HARFull) or as a metadata-only middleware (HARMetadata).

WithContext does NOT register any lifecycle hook — the context owns flushing (e.g. via context.AfterFunc on cancellation).

func (*Client) WithHttpLogging added in v1.40.2

func (c *Client) WithHttpLogging(headerLevel, bodyLevel logger.LogLevel) *Client

WithHttpLogging enables HTTP request/response logging based on the provided log levels.

Parameters:

  • headerLevel: The minimum log level required to log HTTP headers (e.g., logger.Debug)
  • bodyLevel: The minimum log level required to log request/response bodies (e.g., logger.Trace)

Example:

client.WithHttpLogging(logger.Debug, logger.Trace)

This will log headers when debug logging is enabled (-v or -v 1) and bodies when trace logging is enabled (-vv or -v 2 or higher).

Note: When using with cobra commands, ensure UseCobraFlags is called in PersistentPreRun to properly parse -v N syntax.

func (*Client) WithLogger added in v1.52.0

func (c *Client) WithLogger(l logger.Logger) *Client

WithLogger stores l as the client's logger AND, as a side effect, installs a stdout trace middleware whose config is derived from l.GetLevel() via TraceConfigForLogLevel. This makes -v / -vv "just work" by passing the application's standard logger:

NewClient().WithLogger(logger.StandardLogger())

The trace middleware is shared with WithContext (-P http.log=) via TraceToStdout's dedupe — calling both is safe and merges configs.

type CommonsHTTPContext added in v1.52.0

type CommonsHTTPContext interface {
	GetLogger() logger.Logger
	HTTPTraceConfig(feature string) (TraceConfig, bool)
	HARFor(feature string) (collector *har.Collector, path string, level HARLevel)
}

CommonsHTTPContext is the narrow interface a context object implements to drive HTTP-client configuration. xerocli.Context (and could be duty/context.Context) satisfies it; commons/http does not require any other concrete dependency from the application.

HARFor returns the collector, the resolved file path, and the level. A nil collector signals "no HAR for this feature" (the client wires no HAR middleware in that case). Implementations are expected to handle per-path collector deduplication themselves so multiple clients sharing the same output file share one collector.

type HARLevel added in v1.52.0

type HARLevel int

HARLevel selects what a HAR collector captures when attached via WithContext. Borrowed from duty/connection/common.go's Debug/Trace split — at Metadata, only request/response headers + timing are captured (no bodies, no body re-read cost). At Full, the standard collector middleware captures bodies too.

const (
	HARDisabled HARLevel = iota
	HARMetadata
	HARFull
)

type OauthConfig added in v1.17.0

type OauthConfig = middlewares.OauthConfig

type Request

type Request struct {
	// contains filtered or unexported fields
}

Request represents an HTTP request that can be customized and executed. It provides a fluent API for setting headers, query parameters, body, and other options. Request instances should be created using Client.R(ctx).

func (*Request) Body added in v1.13.0

func (r *Request) Body(v any) error

Body sets the request body. Accepts multiple types:

  • io.Reader: Used directly as the body
  • []byte: Wrapped in a bytes.Reader
  • string: Converted to []byte and wrapped
  • Any other type: JSON marshaled

Example:

// JSON body
req.Body(map[string]string{"key": "value"})

// String body
req.Body("raw text data")

// Reader body
req.Body(bytes.NewReader(data))

func (*Request) Debug added in v1.41.1

func (r *Request) Debug() string

func (*Request) Delete added in v1.13.0

func (r *Request) Delete(url string) (*Response, error)

func (*Request) Do added in v1.13.0

func (r *Request) Do(method, reqURL string) (resp *Response, err error)

Do performs an HTTP request with the specified method and URL.

func (*Request) Get added in v1.13.0

func (r *Request) Get(url string) (*Response, error)

Get performs an HTTP GET request to the specified URL.

Example:

resp, err := client.R(ctx).Get("https://api.example.com/users")
if err != nil {
	return err
}
defer resp.Body.Close()

func (*Request) GetHeader added in v1.20.1

func (r *Request) GetHeader(key string) string

func (*Request) GetHeaders added in v1.16.0

func (r *Request) GetHeaders() map[string]string

func (*Request) Header added in v1.13.0

func (r *Request) Header(key, value string) *Request

Header sets a header for the request. Multiple calls with the same key will overwrite previous values.

Example:

resp, err := client.R(ctx).
	Header("Authorization", "Bearer token").
	Header("Content-Type", "application/json").
	GET("/api/data")

func (*Request) HeaderMap added in v1.41.1

func (r *Request) HeaderMap() map[string]string

func (*Request) Patch added in v1.13.0

func (r *Request) Patch(url string, body any) (*Response, error)

func (*Request) Post added in v1.13.0

func (r *Request) Post(url string, body any) (*Response, error)

Post performs an HTTP POST request with the given body. The body can be a string, []byte, io.Reader, or any type that can be JSON marshaled.

Example:

user := map[string]string{"name": "John", "email": "john@example.com"}
resp, err := client.R(ctx).
	Header("Content-Type", "application/json").
	Post("https://api.example.com/users", user)

func (*Request) Put added in v1.13.0

func (r *Request) Put(url string, body any) (*Response, error)

func (*Request) QueryParam added in v1.13.0

func (r *Request) QueryParam(key, value string) *Request

QueryParam sets a query parameter for the request. Multiple calls with the same key will overwrite previous values.

Example:

resp, err := client.R(ctx).
	QueryParam("page", "1").
	QueryParam("limit", "10").
	GET("/api/users")

func (*Request) QueryParamAdd added in v1.31.24

func (r *Request) QueryParamAdd(key, value string) *Request

QueryParamAdd adds a value to a query parameter. Unlike QueryParam, this allows multiple values for the same key.

Example:

// Results in: /api/search?tag=go&tag=http
resp, err := client.R(ctx).
	QueryParamAdd("tag", "go").
	QueryParamAdd("tag", "http").
	GET("/api/search")

func (*Request) Retry added in v1.13.0

func (r *Request) Retry(maxRetries uint, baseDuration time.Duration, exponent float64) *Request

Retry configures retry behavior for this specific request, overriding the client's default retry configuration.

Parameters:

  • maxRetries: Maximum number of retry attempts
  • baseDuration: Initial delay between retries
  • exponent: Multiplier for exponential backoff

Example:

// Retry this request up to 5 times
resp, err := client.R(ctx).
	Retry(5, 500*time.Millisecond, 2.0).
	GET("/flaky-endpoint")

func (*Request) RetryStrategy added in v1.52.0

func (r *Request) RetryStrategy(fn RetryStrategy) *Request

RetryStrategy installs a per-request retry callback, overriding any strategy configured on the client. See Client.RetryStrategy for the full contract; pass nil to clear an inherited strategy and fall back to the legacy Retry()/RetryConfig path for this request.

type Response

type Response struct {
	// The underlying http.Response is embed into Response.
	*http.Response

	// Request is the Response's related Request.
	Request    *Request
	RawRequest *http.Request
}

Response extends the stdlib http.Response type and extends its functionality

func (*Response) AsJSON added in v1.13.0

func (h *Response) AsJSON() (map[string]any, error)

func (*Response) AsMap added in v1.42.2

func (h *Response) AsMap() (map[string]any, error)

func (*Response) AsString

func (r *Response) AsString() (string, error)

func (*Response) Debug added in v1.41.1

func (h *Response) Debug() string

func (*Response) GetHeaders added in v1.16.0

func (r *Response) GetHeaders() map[string]string

func (*Response) GetSSLAge added in v1.13.0

func (h *Response) GetSSLAge() *time.Duration

func (*Response) HeaderMap added in v1.41.1

func (h *Response) HeaderMap() map[string]string

func (*Response) Into added in v1.13.0

func (r *Response) Into(dest any) error

func (*Response) IsJSON added in v1.13.0

func (h *Response) IsJSON() bool

func (*Response) IsOK

func (r *Response) IsOK(responseCodes ...int) bool

IsOK is a convenience method to determine if the response returned a 200 OK

type RetryConfig added in v1.13.0

type RetryConfig struct {
	// Number of retries to attempt
	MaxRetries uint

	// RetryWait specifies the base wait duration between retries
	RetryWait time.Duration

	// Amount to increase RetryWait with each failure, 2.0 is a good option for exponential backoff
	Factor float64
}

type RetryStrategy added in v1.52.0

type RetryStrategy func(resp *Response, err error, attempt int) (retry bool, delay time.Duration)

RetryStrategy decides whether a completed HTTP attempt should be retried. It is called after every attempt with the response (may be nil on a transport error), the transport-level error (may be nil on a non-2xx HTTP response), and the zero-based attempt index.

Return (true, delay) to retry after sleeping delay. A non-positive delay retries immediately. Return (false, _) to stop and surface the underlying attempt result.

When set on a Client or Request via RetryStrategy(...), this callback fully supersedes the legacy RetryConfig-driven exponential-backoff loop: the strategy is responsible for its own attempt cap.

func RetryOnStatus added in v1.52.0

func RetryOnStatus(maxAttempts int, baseDelay time.Duration, statuses ...int) RetryStrategy

RetryOnStatus returns a RetryStrategy that retries on any of the given HTTP status codes (plus transport errors) up to maxAttempts total attempts, using exponential backoff starting at baseDelay (factor 2).

On a 429 response, a Retry-After header is honored over the computed delay. Both delta-seconds and HTTP-date forms are supported.

type TLSConfig added in v1.22.2

type TLSConfig struct {
	// InsecureSkipVerify controls whether a client verifies the server's
	// certificate chain and host name
	InsecureSkipVerify bool
	// HandshakeTimeout defaults to 10 seconds
	HandshakeTimeout time.Duration
	// PEM encoded certificate of the CA to verify the server certificate
	CA string
	// PEM encoded client certificate
	Cert string
	// PEM encoded client private key
	Key string
}

type TraceConfig added in v1.15.0

type TraceConfig = middlewares.TraceConfig

func TraceConfigForLogLevel added in v1.53.0

func TraceConfigForLogLevel(level logger.LogLevel, options ...TraceLevelOption) (TraceConfig, bool)

TraceConfigForLogLevel maps a logger level to a TraceConfig for the stdout trace middleware. The ladder is relative to a configurable base level:

base + 0: access line only
base + 1: query/form params + request/response headers
base + 2: request bodies + concise TLS
base + 3: response bodies

The default base is Debug and can be overridden with http.log.base-level, HTTP_LOG_BASE_LEVEL, or WithTraceBaseLevel.

type TraceLevelOption added in v1.53.0

type TraceLevelOption func(*traceLevelOptions)

TraceLevelOption configures how TraceConfigForLogLevel maps a commons logger level onto the HTTP trace ladder.

func WithTraceBaseLevel added in v1.53.0

func WithTraceBaseLevel(level logger.LogLevel) TraceLevelOption

WithTraceBaseLevel shifts the whole HTTP trace ladder to start at level. With the default base of Debug, -v logs a single access line; with an Info base, a normal info-level logger logs that access line and -v logs headers.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL