httpx

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 22 Imported by: 0

README

httpx 🚀

A small, fluent Go HTTP client built on net/http with typed JSON decoding, tracing, streaming, retries, and configurable connection pooling.

Go Dependencies

Features

  • Fluent builders for GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, and QUERY
  • Generic JSON decoding with ToJSON[T]
  • Configurable timeout and connection pooling
  • Optional retries with bounded backoff
  • Request and response hooks for instrumentation
  • Bounded response reads and typed HTTPError values
  • Streaming response copies with Response.CopyTo
  • Bearer and Basic authentication, plus custom auth providers
  • Multipart uploads, custom headers, query parameters, and raw bodies
  • Structured logging and httptrace-based request diagnostics

Requirements

  • Go 1.22 or newer

Installation

go get github.com/thedevsaddam/httpx

Quick start

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/thedevsaddam/httpx"
)

type Todo struct {
    ID        int    `json:"id"`
    Title     string `json:"title"`
    Completed bool   `json:"completed"`
}

func main() {
    client := httpx.New(
        httpx.WithBaseURL("https://jsonplaceholder.typicode.com"),
        httpx.WithTimeout(10*time.Second),
    )

    todo, err := httpx.ToJSON[Todo](
        client.GET("/todos/1").Send(context.Background()),
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Todo #%d: %s\n", todo.ID, todo.Title)
}

ToJSON[T] decodes a successful JSON response and closes the response body automatically.

Common request examples

GET with query parameters
resp, err := client.GET("/users").
    QueryParam("status", "active").
    QueryParam("limit", "20").
    Header("Accept", "application/json").
    Send(ctx)
if err != nil {
    return err
}
defer resp.Close()

if !resp.IsSuccess() {
    return fmt.Errorf("request failed: %s", resp.Status)
}
POST JSON
type CreateUser struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

user, err := httpx.ToJSON[User](
    client.POST("/users").
        JSON(CreateUser{Name: "Jane Doe", Email: "jane@example.com"}).
        Send(ctx),
)
if err != nil {
    return err
}
fmt.Println("Created user:", user.ID)
POST URL-encoded form

Use Form to send application/x-www-form-urlencoded data, for example when requesting an OAuth token. This is different from Field, which adds a field to a multipart request.

resp, err := client.POST("/oauth/token").
    // DO NOT use both Form and FormValues in a single request
    // For simple key value style
    Form(map[string]string{
        "grant_type":    "client_credentials",
        "client_id":     "my-client",
        "client_secret": "my-secret",
    }).
    // For repeated values per key.
    FormValues(url.Values{
        "grant_type":    "client_credentials",
        "client_id":     "my-client",
        "client_secret": "my-secret",
        "tag":    {"golang", "backend"},
    }).
    Send(ctx)
if err != nil {
    return err
}
defer resp.Close()

if !resp.IsSuccess() {
    return fmt.Errorf("token request failed: %s", resp.Status)
}

Form URL-encodes the values and sets Content-Type: application/x-www-form-urlencoded.

Streaming responses

Send returns a response whose body can be read directly. Use CopyTo to stream a large response to a writer without buffering the entire body in memory:

resp, err := client.GET("/exports/archive").Send(ctx)
if err != nil {
    return err
}
if !resp.IsSuccess() {
    defer resp.Close()
    return fmt.Errorf("download failed: %s", resp.Status)
}

file, err := os.Create("archive.zip")
if err != nil {
    _ = resp.Close()
    return err
}
defer file.Close()

if _, err := resp.CopyTo(file); err != nil {
    return err
}

WithMaxResponseBytes applies to ToJSON and error-body helper reads; it does not limit manual streaming.

Multipart uploads and raw bodies

Multipart upload
resp, err := client.POST("/upload").
    Field("user_id", "12345").
    Fields(url.Values{"tag": {"tag-1", "tag-2"}}. // with repetitive values
    File("avatar", "./avatar.png"). // from file path
    FileReader("attachments", bytes.NewReader(report), "report.pdf"). // from memory
    FileReader("attachments", logFile, "app.log"). // from any reader
    FileReader("attachments", pdfReader, "report.pdf", "application/pdf"). // from reader with content-type
    Send(ctx)
if err != nil {
    return err
}
defer resp.Close()

if !resp.IsSuccess() {
    return fmt.Errorf("upload failed: %s", resp.Status)
}

The current multipart implementation assembles the upload payload in memory. Consider this when uploading large files.

Raw request body
resp, err := client.POST("/messages").
    Header("Content-Type", "text/plain").
    Body(strings.NewReader("hello" )).
    Send(ctx)
if err != nil {
    return err
}
defer resp.Close()
Handle HTTP errors

When ToJSON[T] receives a non-2xx response, it returns an *httpx.HTTPError. Use errors.As to inspect it:

user, err := httpx.ToJSON[User](client.GET("/users/123").Send(ctx))
if err != nil {
    var httpErr *httpx.HTTPError
    if errors.As(err, &httpErr) {
        log.Printf("HTTP %d for %s: %s", httpErr.StatusCode, httpErr.URL, httpErr.Body)
    }
    return err
}
_ = user

HTTPError.Body is a bounded excerpt, not necessarily the full response. Avoid logging it if it could contain secrets or personal information.

Client configuration

Configure the client once and reuse it across requests:

client := httpx.New(
    httpx.WithBaseURL("https://api.example.com/v1"),
    httpx.WithClientName("billing-service"),
    httpx.WithTimeout(10*time.Second),
    httpx.WithHeader("Content-Type", "application/json"),
    httpx.WithHeader("Accept", "application/json"),
    httpx.WithAuth(httpx.NewBearerAuth("<YOUR_TOKEN>")),
    httpx.WithMaxResponseBytes(5 << 20), // 5 MiB for helper reads
    httpx.WithRetryPolicy(httpx.StandardRetryPolicy()),
    httpx.WithPoolConfig(httpx.PoolConfig{
        MaxIdleConns:          100,
        MaxIdleConnsPerHost:   20,
        MaxConnsPerHost:       50,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ResponseHeaderTimeout: 5 * time.Second,
    }),
)
Configuration options
Option Description
WithBaseURL(url) Base URL for relative request paths.
WithTimeout(d) Default request timeout; 30 seconds by default.
WithHeader(key, value) Default request header.
WithQueryParam(key, value) Default query parameter.
WithClientName(name) Sets the X-Client-Name header.
WithAuth(auth) Default authentication provider.
WithLogger(logger) Structured request logging.
WithTracer(tracer) Injects distributed-tracing context into requests.
WithPoolConfig(cfg) Configures the standard transport's connection pool and timeouts.
WithMaxResponseBytes(n) Maximum body size read by JSON and HTTP-error helpers; default is 10 MiB.
WithRetryPolicy(policy) Enables bounded retries. Retries are disabled by default.
WithRequestHook(hook) Hook called before each network attempt.
WithResponseHook(hook) Hook called after response headers arrive.
WithTransport(transport) Supplies a custom *http.Transport.
WithHTTPClient(client) Supplies a custom *http.Client.

For PoolConfig, zero values keep the transport defaults. Pool settings apply when the client uses a standard *http.Transport.

Retries

MaxAttempts includes the initial request. For a standard policy, use StandardRetryPolicy(): three total attempts, retries for network errors and HTTP 429/502/503/504, capped exponential backoff with full jitter, and support for the Retry-After header (capped by MaxBackoff).

client := httpx.New(
    httpx.WithRetryPolicy(httpx.StandardRetryPolicy()),
)

For a custom policy, set Jitter: true to randomize each delay between zero and its exponential backoff cap, and RespectRetryAfter: true to honor Retry-After on retryable responses:

client := httpx.New(
    httpx.WithRetryPolicy(httpx.RetryPolicy{
        MaxAttempts:          3,
        InitialBackoff:       100 * time.Millisecond,
        MaxBackoff:           time.Second,
        RetryableStatusCodes: []int{429, 502, 503, 504},
        RetryNetworkErrors:   true,
        Jitter:               true,
        RespectRetryAfter:    true,
    }),
)

By default, retries are restricted to supported idempotent methods (GET, HEAD, OPTIONS, DELETE, and QUERY) and replayable request bodies. To explicitly opt a request such as POST into the configured retry policy, call .Retryable(). The body must be replayable (for example, one set with .JSON(...)), and repeating the operation must be safe for your application. For operations that create payments, orders, or other side effects, use a server-supported idempotency key; the client cannot guarantee deduplication by itself.

resp, err := client.POST("/orders").
    Header("Idempotency-Key", "order-12345").
    JSON(payload).
    Retryable().
    Send(ctx)

Hooks

Use hooks for metrics, correlation IDs, or instrumentation:

client := httpx.New(
    httpx.WithRequestHook(func(ctx context.Context, req *http.Request) {
        req.Header.Set("X-Request-Source", "billing-service")
    }),
    httpx.WithResponseHook(func(ctx context.Context, resp *http.Response) {
        // Record status and latency in your metrics system.
    }),
)

Hooks may run concurrently, so protect any shared state they access.

Authentication

// Bearer token
client := httpx.New(httpx.WithAuth(httpx.NewBearerAuth("your-token")))

// Basic authentication
client = httpx.New(httpx.WithAuth(httpx.NewBasicAuth("username", "password")))

// API key authentication
client = httpx.New(httpx.WithAuth(httpx.NewAPIKeyAuth("X-API-Key", "your-api-key")))

You can implement the httpx.Auth interface to provide custom authentication. A request can override the client's default with .Auth(auth).

Logging and tracing

Implement httpx.Logger to connect your preferred structured logger:

type MyLogger struct{}

func (l *MyLogger) Debug(ctx context.Context, msg string, kv ...any) {}
func (l *MyLogger) Info(ctx context.Context, msg string, kv ...any)  {}
func (l *MyLogger) Error(ctx context.Context, msg string, kv ...any) {}

Implement httpx.Tracer to inject tracing headers:

type MyTracer struct{}

func (t *MyTracer) Inject(ctx context.Context, req *http.Request) {
    // Inject trace context into req.
}

Call .Debug() on an individual request to log timing and connection diagnostics. Read the trace snapshot with resp.Trace() or the formatted report with resp.Debug(). Trace timings are best-effort and TotalTime ends when response headers arrive, not when the body has been fully read.

Concurrency and response lifecycle

  • Reuse a configured client for concurrent requests; the underlying net/http client and transport support concurrent use.
  • Build a separate request builder for each concurrent operation. Do not mutate and send the same builder concurrently.
  • Hooks and custom auth, logger, and tracer implementations must be safe for concurrent use if shared by requests.
  • Always close response bodies when reading responses directly. ToJSON[T] closes the body automatically.
  • Response.Close() closes the body and attempts to drain a small amount to improve connection reuse.

Testing

Run the test suite and static checks from the module root:

go test ./...
go test -race ./...
go vet ./...

API reference

API Description
New(options...) Creates a client with pooling enabled by default.
client.GET(url) / POST / PUT / PATCH / DELETE / HEAD / OPTIONS / QUERY Creates a request builder.
builder.Header(key, value) / Headers(map) Sets request headers.
builder.QueryParam(key, value) / QueryParams(map) Adds query parameters.
builder.JSON(value) Encodes a JSON request body.
builder.Body(reader) Sets a raw request body.
builder.File(field, path) / Field(key, value) Adds multipart fields.
builder.Auth(auth) / Timeout(d) Overrides request authentication or timeout.
builder.Debug() Enables request diagnostics.
builder.Send(ctx) Executes the request.
resp.IsSuccess() Reports whether the status code is 2xx.
resp.CopyTo(writer) Streams the response body to a writer and closes it.
resp.Close() Closes the response body.
resp.Trace() / resp.Debug() Returns trace information or a formatted report.
ToJSON[T](resp, err) Decodes JSON and closes the response body.

License

The httpx is an open-source software licensed under the MIT License.

Documentation

Overview

Package httpx provides a fluent HTTP client with retries, request tracing and response helpers.

Index

Constants

View Source
const Version = "v1.0.0"

Variables

View Source
var ErrEmptyBody = errors.New("httpx: empty response body")

ErrEmptyBody is returned by ToJSON when a successful response has no body (for example 204).

Functions

func IsTimeout

func IsTimeout(err error) bool

IsTimeout reports whether err is a timeout or deadline error.

func ToBytes

func ToBytes(resp *Response, err error) ([]byte, error)

ToBytes reads and closes a successful response body, subject to the max response size.

func ToJSON

func ToJSON[T any](resp *Response, err error) (T, error)

ToJSON reads, closes, and decodes a successful response into T. An empty body (for example 204) returns ErrEmptyBody.

func ToString

func ToString(resp *Response, err error) (string, error)

ToString reads and closes a successful response body as a string.

Types

type APIKeyAuth

type APIKeyAuth struct {
	Header string
	Key    string
}

APIKeyAuth sends an API key in a request header, for example X-API-Key. Header must be a non-empty header name and Key must be non-empty.

func (APIKeyAuth) Apply

func (a APIKeyAuth) Apply(req *http.Request) error

type APIKeyQueryAuth

type APIKeyQueryAuth struct {
	Param string
	Key   string
}

APIKeyQueryAuth sends an API key as a URL query parameter. Prefer header-based API keys when the server supports them. httpx redacts query strings from its logs, traces and errors, but proxies and servers may still record them.

func (APIKeyQueryAuth) Apply

func (a APIKeyQueryAuth) Apply(req *http.Request) error

type Auth

type Auth interface {
	Apply(req *http.Request) error
}

Auth injects authentication into an outgoing request.

func NewAPIKeyAuth

func NewAPIKeyAuth(header, key string) Auth

NewAPIKeyAuth creates an API key authentication provider that sends key in header. Example: NewAPIKeyAuth("X-API-Key", "your-api-key").

func NewAPIKeyQueryAuth

func NewAPIKeyQueryAuth(param, key string) Auth

NewAPIKeyQueryAuth creates an API key authentication provider that sends key in a query parameter. Example: NewAPIKeyQueryAuth("api_key", "your-api-key").

func NewBasicAuth

func NewBasicAuth(username, password string) Auth

NewBasicAuth creates an HTTP Basic authentication provider.

func NewBearerAuth

func NewBearerAuth(token string) Auth

type BasicAuth

type BasicAuth struct{ Username, Password string }

BasicAuth applies HTTP Basic authentication.

func (BasicAuth) Apply

func (b BasicAuth) Apply(req *http.Request) error

type BearerAuth

type BearerAuth struct{ Token string }

BearerAuth applies a bearer token.

func (BearerAuth) Apply

func (b BearerAuth) Apply(req *http.Request) error

type Client

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

Client wraps http.Client and provides defaults and fluent request builders. A Client is safe for concurrent use once constructed.

func New

func New(options ...Option) *Client

New creates a client with connection pooling enabled by default.

func (*Client) Close

func (c *Client) Close()

Close releases idle connections held by the client's transport.

func (*Client) DELETE

func (c *Client) DELETE(url string) *RequestBuilder

func (*Client) GET

func (c *Client) GET(url string) *RequestBuilder

Standard HTTP method constructors.

func (*Client) HEAD

func (c *Client) HEAD(url string) *RequestBuilder

func (*Client) OPTIONS

func (c *Client) OPTIONS(url string) *RequestBuilder

func (*Client) PATCH

func (c *Client) PATCH(url string) *RequestBuilder

func (*Client) POST

func (c *Client) POST(url string) *RequestBuilder

func (*Client) PUT

func (c *Client) PUT(url string) *RequestBuilder

func (*Client) QUERY

func (c *Client) QUERY(url string) *RequestBuilder

QUERY initiates a safe, idempotent server-side query. The query definition is typically sent in the request body, which should have an appropriate Content-Type. Servers and intermediaries must support the QUERY method for this to work.

type HTTPError

type HTTPError struct {
	Method     string
	URL        string
	StatusCode int
	Status     string
	Header     http.Header
	Body       string
}

HTTPError represents a non-2xx HTTP response. Body is a bounded excerpt (about 4 KiB). URL never includes the query string.

func (*HTTPError) Error

func (e *HTTPError) Error() string

type Logger

type Logger interface {
	Debug(ctx context.Context, msg string, keysAndValues ...any)
	Info(ctx context.Context, msg string, keysAndValues ...any)
	Error(ctx context.Context, msg string, keysAndValues ...any)
}

Logger is the optional structured logging interface.

type Middleware

type Middleware func(http.RoundTripper) http.RoundTripper

Middleware wraps a RoundTripper, for example to add OpenTelemetry, metrics or rate limiting. Middlewares run in the order given: the first one is the outermost.

type Option

type Option func(*Client)

Option configures a Client. Options only record intent; the HTTP client is built once at the end of New, so the order of options does not matter.

func WithAuth

func WithAuth(auth Auth) Option

WithAuth sets default authentication.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL sets a base URL prepended to relative request paths. Path segments of the base are preserved: base "https://x.com/v1" and path "/users" give "https://x.com/v1/users".

func WithCheckRedirect

func WithCheckRedirect(fn func(req *http.Request, via []*http.Request) error) Option

WithCheckRedirect sets the redirect policy. Return http.ErrUseLastResponse to stop following.

func WithClientName

func WithClientName(value string) Option

WithClientName sets a Header `X-Client-Name`.

func WithCookieJar

func WithCookieJar(jar http.CookieJar) Option

WithCookieJar sets the cookie jar.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient uses a copy of a custom *http.Client; the original is never modified. Its Timeout becomes the default request timeout unless WithTimeout is also given.

func WithHeader

func WithHeader(key, value string) Option

WithHeader sets a default header.

func WithLogger

func WithLogger(logger Logger) Option

WithLogger sets structured logging.

func WithMaxResponseBytes

func WithMaxResponseBytes(n int64) Option

WithMaxResponseBytes sets the maximum body size consumed by ToJSON, ToBytes and ToString. Send still exposes a streaming body; callers can stream arbitrarily large responses themselves.

func WithMiddleware

func WithMiddleware(m ...Middleware) Option

WithMiddleware appends RoundTripper middlewares (tracing, metrics, rate limiting, ...).

func WithPoolConfig

func WithPoolConfig(cfg PoolConfig) Option

WithPoolConfig configures connection pooling. Zero values retain the transport defaults. It requires the underlying transport to be an *http.Transport.

func WithProxy

func WithProxy(proxy func(*http.Request) (*url.URL, error)) Option

WithProxy sets the proxy function. Pass nil to disable proxies entirely.

func WithQueryParam

func WithQueryParam(key, value string) Option

WithQueryParam sets a default query parameter.

func WithRequestHook

func WithRequestHook(h RequestHook) Option

func WithResponseHook

func WithResponseHook(h ResponseHook) Option

func WithRetryPolicy

func WithRetryPolicy(p RetryPolicy) Option

WithRetryPolicy configures opt-in retries. Retries are limited to idempotent methods and replayable bodies.

func WithTLSConfig

func WithTLSConfig(cfg *tls.Config) Option

WithTLSConfig sets the TLS client configuration (custom CAs, client certificates for mTLS, ...). It requires the underlying transport to be an *http.Transport.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the default timeout for requests. It covers the whole call, including all retry attempts, backoff waits and (until Close) reading the response body. Zero disables the timeout.

func WithTracer

func WithTracer(tracer Tracer) Option

WithTracer sets distributed trace propagation.

func WithTransport

func WithTransport(transport http.RoundTripper) Option

WithTransport sets a custom transport.

type PoolConfig

type PoolConfig struct {
	MaxIdleConns          int
	MaxIdleConnsPerHost   int
	MaxConnsPerHost       int
	IdleConnTimeout       time.Duration
	TLSHandshakeTimeout   time.Duration
	ResponseHeaderTimeout time.Duration
}

PoolConfig configures the standard HTTP transport connection pool.

type RequestBuilder

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

RequestBuilder builds an individual HTTP request.

func (*RequestBuilder) Auth

func (rb *RequestBuilder) Auth(auth Auth) *RequestBuilder

Auth overrides client-level authentication for this request.

func (*RequestBuilder) Body

func (rb *RequestBuilder) Body(body io.Reader) *RequestBuilder

Body sets a raw request body. Retries need a replayable body: *bytes.Buffer, *bytes.Reader and *strings.Reader qualify.

func (*RequestBuilder) Debug

func (rb *RequestBuilder) Debug() *RequestBuilder

Debug enables trace output for this request. The report is logged after response headers arrive (or when the request fails), to the logger or to stderr when none is configured.

func (*RequestBuilder) Field

func (rb *RequestBuilder) Field(key, value string) *RequestBuilder

Field adds a multipart text field.

func (*RequestBuilder) Fields

func (rb *RequestBuilder) Fields(fields url.Values) *RequestBuilder

Fields adds multiple multipart text field values.

func (*RequestBuilder) File

func (rb *RequestBuilder) File(fieldName, filePath string) *RequestBuilder

File attaches a local file as a multipart/form-data upload. It can be called several times, including with the same field name; parts are sent in call order.

func (*RequestBuilder) FileReader

func (rb *RequestBuilder) FileReader(fieldName string, r io.Reader, filename string, contentType ...string) *RequestBuilder

FileReader attaches content from r as a multipart/form-data file part named fieldName, using filename as the uploaded file name. It can be called multiple times and combined with File and Field.

The reader is consumed once, when Send builds the multipart body; the body is buffered in memory so retries can replay it. The caller keeps ownership of r and must close it if it is an io.Closer. Because r is consumed, a builder with FileReader cannot be Sent a second time unless the reader is reset by the caller.

func (*RequestBuilder) Form

func (rb *RequestBuilder) Form(fields map[string]string) *RequestBuilder

Form sets URL-encoded form data with one value per key.

func (*RequestBuilder) FormValues

func (rb *RequestBuilder) FormValues(values url.Values) *RequestBuilder

FormValues sets URL-encoded form data. It supports multiple values for the same key.

func (*RequestBuilder) Header

func (rb *RequestBuilder) Header(key, value string) *RequestBuilder

Header sets a request header.

func (*RequestBuilder) Headers

func (rb *RequestBuilder) Headers(headers map[string]string) *RequestBuilder

Headers sets multiple request headers.

func (*RequestBuilder) IdempotencyKey

func (rb *RequestBuilder) IdempotencyKey(key string) *RequestBuilder

IdempotencyKey sets the Idempotency-Key header and marks the request Retryable, which makes retrying POST and PATCH safe against servers that honor the key.

func (*RequestBuilder) JSON

func (rb *RequestBuilder) JSON(v any) *RequestBuilder

JSON encodes v as JSON. Encoding errors are returned by Send rather than hidden in the body. HTML characters (<, >, &) are not escaped.

func (*RequestBuilder) PathParam

func (rb *RequestBuilder) PathParam(name, value string) *RequestBuilder

PathParam replaces "{name}" in the URL with the escaped value, e.g. "/users/{id}".

func (*RequestBuilder) QueryParam

func (rb *RequestBuilder) QueryParam(key, value string) *RequestBuilder

QueryParam appends a query parameter.

func (*RequestBuilder) QueryParams

func (rb *RequestBuilder) QueryParams(params map[string]string) *RequestBuilder

QueryParams sets query parameters, replacing values for matching keys.

func (*RequestBuilder) Retryable

func (rb *RequestBuilder) Retryable() *RequestBuilder

Retryable explicitly allows this request to be retried when the configured RetryPolicy matches a retryable network error or status code. Use only when repeating the operation is safe, typically with a server-supported idempotency key. Request bodies must be replayable.

func (*RequestBuilder) Send

func (rb *RequestBuilder) Send(ctx context.Context) (*Response, error)

Send executes the request and returns the response. The caller must close the response body. The request timeout covers every attempt, and stays active until the body is closed.

func (*RequestBuilder) Timeout

func (rb *RequestBuilder) Timeout(timeout time.Duration) *RequestBuilder

Timeout overrides the client-level timeout for this request. It covers all retry attempts.

type RequestHook

type RequestHook func(context.Context, *http.Request)

RequestHook runs immediately before each network attempt. Hooks must be safe for concurrent calls.

type Response

type Response struct {
	*http.Response
	// contains filtered or unexported fields
}

Response wraps http.Response and exposes trace information and helpers.

func (*Response) Close

func (r *Response) Close() error

Close closes the body. It drains up to 4 KiB to improve keep-alive reuse without allowing an unexpectedly large response to block Close indefinitely.

func (*Response) CopyTo

func (r *Response) CopyTo(dst io.Writer) (int64, error)

CopyTo streams the response body to dst without buffering the entire response in memory. It closes the response body when finished.

func (*Response) Debug

func (r *Response) Debug() string

Debug returns a formatted trace report for this response.

func (*Response) IsSuccess

func (r *Response) IsSuccess() bool

IsSuccess reports whether the response status is 2xx.

func (*Response) Trace

func (r *Response) Trace() TraceInfo

Trace returns a snapshot of the request timing information.

type ResponseHook

type ResponseHook func(context.Context, *http.Response)

ResponseHook runs after response headers arrive on each attempt. Hooks must be safe for concurrent calls.

type RetryPolicy

type RetryPolicy struct {
	MaxAttempts          int
	InitialBackoff       time.Duration
	MaxBackoff           time.Duration
	RetryableStatusCodes []int
	RetryNetworkErrors   bool
	Jitter               bool
	RespectRetryAfter    bool
}

RetryPolicy controls retries. MaxAttempts includes the first attempt. A value below 2 means no retries. Jitter enables full jitter: each backoff is randomized between zero and the exponential backoff cap. When RespectRetryAfter is set and the server asks for a delay longer than MaxBackoff (when positive), the request is not retried and the response is returned to the caller instead of hammering the server too early.

func StandardRetryPolicy

func StandardRetryPolicy() RetryPolicy

StandardRetryPolicy returns a conservative policy for common transient failures. It makes up to three total attempts, retries network errors and HTTP 429/502/503/504, uses capped exponential backoff with full jitter, and honors Retry-After when present.

type TraceInfo

type TraceInfo struct {
	Method         string
	URL            string
	Path           string
	StatusCode     int
	DNSLookup      time.Duration
	ConnTime       time.Duration
	TCPConnTime    time.Duration
	TLSHandshake   time.Duration
	ServerTime     time.Duration
	ResponseTime   time.Duration
	TotalTime      time.Duration
	IsConnReused   bool
	IsConnWasIdle  bool
	ConnIdleTime   time.Duration
	RequestAttempt int
	RemoteAddr     string
	// contains filtered or unexported fields
}

TraceInfo contains timing and connection information collected with net/http/httptrace. Durations are best-effort and some fields remain zero when a connection is reused, a proxy is involved, or the transport does not emit the corresponding hook. TotalTime measures the time until response headers are available. URL never includes the query string, which may carry secrets.

func (*TraceInfo) Snapshot

func (t *TraceInfo) Snapshot() TraceInfo

Snapshot returns a copy of the trace fields, safe to inspect while the request is running.

func (*TraceInfo) String

func (t *TraceInfo) String() string

String formats the trace in a human-readable diagnostic report.

type Tracer

type Tracer interface {
	Inject(ctx context.Context, req *http.Request)
}

Tracer injects distributed tracing information into an outgoing request.

Jump to

Keyboard shortcuts

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