# Changelog All notable changes to this module will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.9.0] - 2026-03-18 ### Added - `Client` interface: `Do(req *http.Request) (*http.Response, error)`. - `Config` struct: fields `Name`, `Timeout` (default `30s`), `DialTimeout` (default `5s`), `MaxRetries` (default `3`), `RetryDelay` (default `1s`), `CBThreshold` (default `10`), `CBTimeout` (default `1m`); settable via `HTTP_*` environment variables. - `DefaultConfig() Config`: returns a `Config` populated with all default values. - `New(logger logz.Logger, cfg Config) Client`: constructs a client with a `gobreaker` circuit breaker wrapping an `avast/retry-go` retry loop. The circuit breaker trips after `CBThreshold` consecutive failures and resets after `CBTimeout`. - `NewWithDefaults(logger logz.Logger) Client`: convenience constructor; equivalent to `New(logger, DefaultConfig())`. - Retry behaviour: up to `MaxRetries` attempts with exponential backoff (`retry.BackOffDelay`). Only network errors and HTTP 5xx responses are retried; 4xx responses are not. - Circuit breaker behaviour: the breaker wraps the full retry sequence, so one fully-exhausted retry sequence counts as one failure. State transitions are logged at `Warn` level with `name`, `from`, and `to` fields. - Request ID propagation: `logz.GetRequestID(ctx)` is called on each attempt; if a request ID is present, it is forwarded as the `X-Request-ID` request header. - Per-request structured logging: successful requests emit an `Info` log with `method`, `url`, `status`, and `latency` fields; failed individual attempts emit a `Debug` log. - Error mapping on `Do`: open circuit → `ErrUnavailable`; post-retry HTTP error response → `MapStatusToError`; network/timeout error → `ErrInternal`. - `DoJSON[T any](ctx context.Context, client Client, req *http.Request) (*T, error)`: generic free function that executes a request and decodes the JSON response body into `T`; returns `*T` on success and a xerrors-typed error for network failures, HTTP 4xx/5xx responses, unreadable bodies, or JSON decode failures. - `MapStatusToError(code int, msg string) error` (exported): maps HTTP status codes to xerrors codes — `404` → `ErrNotFound`, `400` → `ErrInvalidInput`, `401` → `ErrUnauthorized`, `403` → `ErrPermissionDenied`, `409` → `ErrAlreadyExists`, `429` → `ErrUnavailable`, all others → `ErrInternal`. - Dial timeout applied via a custom `net.Dialer` on the `http.Transport`, independent of the per-request `Timeout`. ### Design Notes - The circuit breaker wraps the retry loop rather than individual attempts; a full set of exhausted retries registers as a single failure against the breaker threshold, preventing overly aggressive tripping. - `DoJSON` is a free generic function rather than a method so it works with any `Client` implementation, including mocks, without requiring a concrete type. - The module has no lifecycle (no `OnInit`/`OnStart`/`OnStop`) and does not depend on `launcher` or `health`; it is a stateless constructor suitable for use at any tier. [0.9.0]: https://code.nochebuena.dev/go/httpclient/releases/tag/v0.9.0