Documentation
¶
Overview ¶
Package httpclient is a thin, generics-friendly fasthttp client wrapper with built-in Elastic APM instrumentation (via apmcore), pluggable structured-log hook, and optional retry-with-backoff.
Top-level functions (GET[O], POST[O], …) cover the 99% case:
type charge struct{ ID string `json:"id"` }
out, err := httpclient.POST[charge](ctx, httpclient.RequestOptions{
URL: "https://api.example.com/charge",
Headers: httpclient.JSONHeaders(),
Data: map[string]any{"amount": 100},
})
Configure once at boot:
httpclient.UseClient(&fasthttp.Client{ReadTimeout: 10*time.Second})
httpclient.SetHook(func(r httpclient.Record) {
logger.LogCtx(r.Ctx).Info("← outgoing", zap.Any("outgoing", buildOutgoing(r)))
})
All requests are wrapped in an APM exit span and propagate the active transaction's traceparent header automatically.
Index ¶
- func AddHook(h Hook)
- func DELETE[O any](ctx context.Context, opts RequestOptions) (*O, error)
- func Do(ctx context.Context, method string, opts RequestOptions) ([]byte, error)
- func FormHeaders() map[string]string
- func GET[O any](ctx context.Context, opts RequestOptions) (*O, error)
- func JSONHeaders() map[string]string
- func PATCH[O any](ctx context.Context, opts RequestOptions) (*O, error)
- func POST[O any](ctx context.Context, opts RequestOptions) (*O, error)
- func PUT[O any](ctx context.Context, opts RequestOptions) (*O, error)
- func Request[O any](ctx context.Context, method string, opts RequestOptions) (*O, error)
- func SetConfig(c *Config)
- func SetHook(h Hook)
- func UseClient(c *fasthttp.Client)
- type Config
- type Hook
- type Record
- type RequestOptions
- type RetryPolicy
- type StatusError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddHook ¶ added in v0.7.0
func AddHook(h Hook)
AddHook appends h to the current hook chain. If no hook is installed, h becomes the sole hook. Subsequent calls compose without dropping prior hooks — safe to call multiple times at boot (e.g. log hook + audit hook).
func DELETE ¶
func DELETE[O any](ctx context.Context, opts RequestOptions) (*O, error)
DELETE issues a DELETE and decodes the body as O.
func Do ¶
Do executes a single fasthttp call described by opts. Returns the raw response body and an error. Status codes outside [200, 300) produce a non-nil error but the body is still returned.
The call is wrapped in an APM exit span via apmcore.TraceFastHTTPCall and the configured Hook is invoked once per attempt.
func FormHeaders ¶
FormHeaders returns a map with Content-Type: application/x-www-form-urlencoded.
func GET ¶
func GET[O any](ctx context.Context, opts RequestOptions) (*O, error)
GET issues a GET and decodes the body as O.
func JSONHeaders ¶
JSONHeaders returns a map with Content-Type: application/json. Useful shorthand in RequestOptions.Headers.
func PATCH ¶
func PATCH[O any](ctx context.Context, opts RequestOptions) (*O, error)
PATCH issues a PATCH and decodes the body as O.
func POST ¶
func POST[O any](ctx context.Context, opts RequestOptions) (*O, error)
POST issues a POST and decodes the body as O.
func PUT ¶
func PUT[O any](ctx context.Context, opts RequestOptions) (*O, error)
PUT issues a PUT and decodes the body as O.
func Request ¶
Request is the generic verb-agnostic helper used by GET / POST / … It executes the call and unmarshals the response body into *O.
If the call returns a *StatusError, both the body and the error are returned — so callers can still inspect partial responses.
func SetConfig ¶
func SetConfig(c *Config)
SetConfig replaces the active configuration. Pass nil to restore defaults.
Types ¶
type Hook ¶
type Hook func(Record)
Hook is invoked once per attempt — including retried ones — right after the call returns. Hooks must not panic; use them for logging or metrics, not control flow.
type Record ¶
type Record struct {
Ctx context.Context
Method string
URL string
Status int
ResponseTime time.Duration
ReqHeaders map[string]string
ReqBody []byte // bytes that hit the wire (already JSON or form-encoded)
ResHeaders map[string]string
ResBody []byte
Err error
Attempt int // 1-based; >1 means this is a retry
RetryExhausted bool // true on the final attempt when retries are exhausted due to a retryable failure
}
Record carries everything a hook (logger / auditor) needs to know about an outgoing call.
type RequestOptions ¶
type RequestOptions struct {
URL string
QueryString map[string]string
Headers map[string]string
// Data is the request body. Any value is marshalled with sonic
// (JSON) by default; when Headers["Content-Type"] is
// "application/x-www-form-urlencoded" and Data is a map[string]any
// or map[string]string, it is form-encoded instead.
Data any
// Timeout overrides the per-call timeout. Zero falls back to
// Config.DefaultTimeout.
Timeout time.Duration
// Retry policy. Zero attempts → no retry (one call). Each attempt
// produces its own APM span.
Retry RetryPolicy
}
RequestOptions describes a single outgoing call. All fields are optional except URL.
type RetryPolicy ¶
type RetryPolicy struct {
// MaxAttempts is the total number of calls (1 = no retry).
MaxAttempts int
// InitialBackoff is the wait before the second attempt.
InitialBackoff time.Duration
// MaxBackoff caps the per-attempt wait.
MaxBackoff time.Duration
// Multiplier scales the backoff after each attempt (default 2 if 0).
Multiplier float64
// ShouldRetry decides whether err+status warrants another attempt.
// Nil → retry on transport error or 5xx.
ShouldRetry func(status int, err error) bool
}
RetryPolicy describes how many times to retry a failed call and how to wait between attempts.
type StatusError ¶
StatusError indicates the request reached the server but the status code is outside [200, 300). Body is preserved.
func (*StatusError) Error ¶
func (e *StatusError) Error() string