Documentation
¶
Index ¶
- Constants
- func EnsureTraceID(ctx context.Context) string
- func GenerateTraceParent() string
- func IsErrorType(err error, errorType ErrorType) bool
- func IsHTTPStatusError(err error, statusCode int) bool
- func IsJOSEError(err error) bool
- func IsSuccessStatus(statusCode int) bool
- func TraceIDFromContext(ctx context.Context) (string, bool)
- func TraceParentFromContext(ctx context.Context) (string, bool)
- func TraceStateFromContext(ctx context.Context) (string, bool)
- func WithTraceID(ctx context.Context, traceID string) context.Context
- func WithTraceParent(ctx context.Context, traceParent string) context.Context
- func WithTraceState(ctx context.Context, traceState string) context.Context
- type BasicAuth
- type Builder
- func (b *Builder) Build() Client
- func (b *Builder) WithBasicAuth(username, password string) *Builder
- func (b *Builder) WithDefaultHeader(key, value string) *Builder
- func (b *Builder) WithHTTPClient(client *nethttp.Client) *Builder
- func (b *Builder) WithJOSE(cfg JOSEConfig) *Builder
- func (b *Builder) WithLogPayloads(enabled bool) *Builder
- func (b *Builder) WithMaxPayloadLogBytes(n int) *Builder
- func (b *Builder) WithPeerName(name string) *Builder
- func (b *Builder) WithRequestInterceptor(interceptor RequestInterceptor) *Builder
- func (b *Builder) WithResponseInterceptor(interceptor ResponseInterceptor) *Builder
- func (b *Builder) WithRetries(maxRetries int, retryDelay time.Duration) *Builder
- func (b *Builder) WithTimeout(timeout time.Duration) *Builder
- func (b *Builder) WithTraceIDExtractor(extractor func(_ context.Context) (string, bool)) *Builder
- func (b *Builder) WithTraceIDGenerator(gen func() string) *Builder
- func (b *Builder) WithTraceIDHeader(name string) *Builder
- func (b *Builder) WithTransport(transport nethttp.RoundTripper) *Builder
- func (b *Builder) WithW3CTrace(enabled bool) *Builder
- type Client
- type ClientError
- func NewHTTPError(message string, statusCode int, body []byte) ClientError
- func NewInterceptorError(message, stage string, wrapped error) ClientError
- func NewNetworkError(message string, wrapped error) ClientError
- func NewTimeoutError(message string, timeout time.Duration) ClientError
- func NewValidationError(message, field string) ClientError
- type Config
- type ErrorType
- type JOSEConfig
- type JOSETransport
- type Request
- type RequestInterceptor
- type Response
- type ResponseInterceptor
- type Stats
Constants ¶
const ( // DefaultTimeout is the default request timeout duration DefaultTimeout = 30 * time.Second // DefaultMaxRetries is the default maximum number of retries for failed requests DefaultMaxRetries = 0 // DefaultRetryDelay is the default delay between retries DefaultRetryDelay = 1 * time.Second )
const ( // HeaderXRequestID is the standard header name for request tracing HeaderXRequestID = gobrickstrace.HeaderXRequestID // HeaderTraceParent is the W3C trace context header name HeaderTraceParent = gobrickstrace.HeaderTraceParent // HeaderTraceState is the W3C trace context "tracestate" header name HeaderTraceState = gobrickstrace.HeaderTraceState )
const DefaultMaxJOSEBodyBytes int64 = 10 << 20 // 10 MiB
DefaultMaxJOSEBodyBytes caps the size of an inbound JOSE response body when no explicit MaxResponseBytes is set on JOSETransport. 10 MiB is comfortably larger than any expected VTS-style payload (token responses are typically <2 KiB) but small enough to bound peak memory if a counterparty (or attacker) sends a malicious response. Defense-in-depth against memory exhaustion.
Variables ¶
This section is empty.
Functions ¶
func EnsureTraceID ¶
EnsureTraceID returns an existing trace ID from context or generates a new one
func GenerateTraceParent ¶
func GenerateTraceParent() string
GenerateTraceParent creates a minimal W3C traceparent header value. Format: version(2)-trace-id(32)-span-id(16)-flags(2), e.g., "00-<32>-<16>-01"
func IsErrorType ¶
IsErrorType checks if an error is of a specific type
func IsHTTPStatusError ¶
IsHTTPStatusError checks if an error is an HTTP error with a specific status code
func IsJOSEError ¶ added in v0.30.0
IsJOSEError reports whether err is a JOSE crypto failure — kept as a thin re-export of jose.IsError for discoverability from the httpclient package, since transport callers typically already import httpclient and may not realize the canonical helper lives in jose.
func IsSuccessStatus ¶
IsSuccessStatus checks if a status code represents success (2xx). Uses stdlib constants for self-documenting boundaries.
func TraceIDFromContext ¶
TraceIDFromContext returns a trace ID from context if present
func TraceParentFromContext ¶
TraceParentFromContext returns a traceparent from context if present
func TraceStateFromContext ¶
TraceStateFromContext returns a tracestate from context if present
func WithTraceID ¶
WithTraceID adds a trace ID to the context for HTTP client propagation
func WithTraceParent ¶
WithTraceParent adds a W3C traceparent value to the context
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder provides a fluent interface for configuring the REST client
func NewBuilder ¶
NewBuilder creates a new client builder
func (*Builder) WithBasicAuth ¶
WithBasicAuth sets basic authentication credentials
func (*Builder) WithDefaultHeader ¶
WithDefaultHeader adds a default header that will be sent with all requests
func (*Builder) WithHTTPClient ¶
WithHTTPClient allows providing a custom *http.Client instance. Build shallow-copies the provided client and never mutates it: the caller's client keeps its own Transport and Timeout. If the provided client's Timeout is zero, the copy gets the builder's configured Timeout. The copy's Transport is preserved unless explicitly overridden via WithTransport or WithJOSE. The copy is shallow: reference fields such as the cookie Jar remain shared with the caller's client.
func (*Builder) WithJOSE ¶ added in v0.30.0
func (b *Builder) WithJOSE(cfg JOSEConfig) *Builder
WithJOSE configures a JOSETransport that signs+encrypts every outbound request body and decrypts+verifies application/jose response bodies. Pass cfg.Inbound = nil when the counterparty does not return JOSE-wrapped responses.
Composition: WithJOSE wraps whatever transport was set via an earlier WithTransport call — so that transport customization remains in the chain below the JOSE layer. A Transport configured directly on the *http.Client passed to WithHTTPClient is NOT threaded through: Build() sets the transport on the built client's copied *http.Client whenever WithTransport or WithJOSE set b.transport (the client passed to WithHTTPClient is never modified), so use WithTransport if a custom RoundTripper needs to survive beneath WithJOSE. Calling WithTransport AFTER WithJOSE replaces the JOSE transport entirely.
Per-attempt freshness: because httpclient retries by re-running the request build loop, each retry produces a freshly-sealed payload — useful for protocols that require unique iat/jti claims per attempt.
func (*Builder) WithLogPayloads ¶ added in v0.37.0
WithLogPayloads enables debug-level logging of request and response bodies. WARNING: enable only in development/staging — even with SensitiveDataFilter active, JSON bodies are parsed and field-masked but the full body surface is widened significantly. Non-JSON bodies (form-urlencoded, binary, etc.) are never emitted; only the content-type and byte count are logged to prevent credential pairs from reaching the log stream.
func (*Builder) WithMaxPayloadLogBytes ¶ added in v0.37.0
WithMaxPayloadLogBytes caps the number of body bytes inspected per direction when WithLogPayloads is enabled. Values <= 0 are ignored; the built-in fallback (1024) applies.
func (*Builder) WithPeerName ¶ added in v0.37.0
WithPeerName sets a low-cardinality logical service name attached to every metric emitted by this client. Intended for SLO attribution (e.g., "stripe", "visa-vts"). When unset, only the high-cardinality server.address is recorded.
func (*Builder) WithRequestInterceptor ¶
func (b *Builder) WithRequestInterceptor(interceptor RequestInterceptor) *Builder
WithRequestInterceptor adds a request interceptor
func (*Builder) WithResponseInterceptor ¶
func (b *Builder) WithResponseInterceptor(interceptor ResponseInterceptor) *Builder
WithResponseInterceptor adds a response interceptor
func (*Builder) WithRetries ¶
WithRetries sets the retry configuration
func (*Builder) WithTimeout ¶
WithTimeout sets the request timeout
func (*Builder) WithTraceIDExtractor ¶
WithTraceIDExtractor sets a function to extract a trace ID from context
func (*Builder) WithTraceIDGenerator ¶
WithTraceIDGenerator sets the generator used when no trace ID is present
func (*Builder) WithTraceIDHeader ¶
WithTraceIDHeader sets the header name used for the trace ID (default: X-Request-ID)
func (*Builder) WithTransport ¶
func (b *Builder) WithTransport(transport nethttp.RoundTripper) *Builder
WithTransport sets a custom RoundTripper while still letting the builder manage other client settings.
func (*Builder) WithW3CTrace ¶
WithW3CTrace enables or disables W3C trace context propagation
type Client ¶
type Client interface {
Get(ctx context.Context, req *Request) (*Response, error)
Post(ctx context.Context, req *Request) (*Response, error)
Put(ctx context.Context, req *Request) (*Response, error)
Patch(ctx context.Context, req *Request) (*Response, error)
Delete(ctx context.Context, req *Request) (*Response, error)
Do(ctx context.Context, method string, req *Request) (*Response, error)
}
Client defines the REST client interface for making HTTP requests
type ClientError ¶
ClientError represents different types of REST client errors
func NewHTTPError ¶
func NewHTTPError(message string, statusCode int, body []byte) ClientError
NewHTTPError creates a new HTTP error
func NewInterceptorError ¶
func NewInterceptorError(message, stage string, wrapped error) ClientError
NewInterceptorError creates a new interceptor error
func NewNetworkError ¶
func NewNetworkError(message string, wrapped error) ClientError
NewNetworkError creates a new network error
func NewTimeoutError ¶
func NewTimeoutError(message string, timeout time.Duration) ClientError
NewTimeoutError creates a new timeout error
func NewValidationError ¶
func NewValidationError(message, field string) ClientError
NewValidationError creates a new validation error
type Config ¶
type Config struct {
Timeout time.Duration
MaxRetries int
RetryDelay time.Duration
RequestInterceptors []RequestInterceptor
ResponseInterceptors []ResponseInterceptor
BasicAuth *BasicAuth
DefaultHeaders map[string]string
// LogPayloads enables debug-level logging of headers and body payloads
LogPayloads bool
// MaxPayloadLogBytes caps the number of body bytes logged when LogPayloads is enabled
MaxPayloadLogBytes int
// TraceIDHeader configures the header name used for trace ID propagation (default: X-Request-ID)
TraceIDHeader string
// NewTraceID generates a new trace ID when none is present (default: uuid)
NewTraceID func() string
// TraceIDExtractor allows advanced extraction of a trace ID from context; return ok=false to fallback to generator
TraceIDExtractor func(_ context.Context) (traceID string, ok bool)
// EnableW3CTrace enables W3C Trace Context (traceparent/tracestate) propagation and generation
EnableW3CTrace bool
// PeerName is a low-cardinality logical service name attached to every metric emitted
// by this client. Intended for SLO attribution (e.g., "stripe", "visa-vts").
// When unset, only the high-cardinality server.address is recorded.
PeerName string
}
Config holds the REST client configuration
type JOSEConfig ¶ added in v0.30.0
type JOSEConfig struct {
// Outbound is required: the policy used to sign+encrypt every outbound request body.
Outbound *jose.Policy
// Inbound is optional: when set, application/jose response bodies are decrypted+verified.
// Plaintext responses (e.g., pre-trust error envelopes from the counterparty) pass
// through unmodified.
Inbound *jose.Policy
// Resolver supplies keys for both Outbound and Inbound directions.
Resolver jose.KeyResolver
}
JOSEConfig groups the JOSE policy and resolver passed to Builder.WithJOSE. A struct is used (rather than positional parameters) so future fields — clock override, replay-cache hook, per-call policy resolver — can be added without changing the WithJOSE signature.
type JOSETransport ¶ added in v0.30.0
type JOSETransport struct {
// Inner is the underlying RoundTripper that performs the actual HTTP exchange.
// Nil defaults to nethttp.DefaultTransport.
Inner nethttp.RoundTripper
// Outbound is required: the policy used to sign+encrypt every outbound request body.
// A nil Outbound disables outbound wrapping entirely (the transport delegates to Inner).
Outbound *jose.Policy
// Inbound is optional: when set, application/jose responses are decrypted+verified.
// Other response Content-Types pass through unmodified so plaintext error envelopes
// from JOSE-aware counterparties (e.g., GoBricks pre-trust failures) remain readable.
Inbound *jose.Policy
// Resolver supplies keys for both Outbound (sign/encrypt) and Inbound (decrypt/verify).
// Required when either policy is set.
Resolver jose.KeyResolver
// MaxResponseBytes bounds the response body read when Inbound is set. Zero means
// use DefaultMaxJOSEBodyBytes. A negative value disables the cap entirely (NOT
// recommended for untrusted counterparties).
MaxResponseBytes int64
}
JOSETransport is an http.RoundTripper that signs+encrypts outbound request bodies (jose.Seal) and decrypts+verifies inbound response bodies (jose.Open) using a fixed pair of policies and a single KeyResolver.
Architectural placement: JOSETransport sits below the httpclient retry loop, so each retry attempt produces a freshly-sealed request — important for protocols that require unique iat/jti claims per attempt (Visa Token Services and similar).
Response Content-Type discrimination: only application/jose responses are unwrapped; other Content-Types pass through untouched. This mirrors the GoBricks server's hybrid error envelope — pre-trust failures from the counterparty come back as plaintext minimal JSON because the peer was never authenticated, and the transport must not attempt to decrypt those.
type RequestInterceptor ¶
RequestInterceptor is called before sending the request
func NewTraceIDInterceptor ¶
func NewTraceIDInterceptor() RequestInterceptor
NewTraceIDInterceptor creates a request interceptor that adds trace ID headers This provides an alternative approach for users who want explicit control
func NewTraceIDInterceptorFor ¶
func NewTraceIDInterceptorFor(header string) RequestInterceptor
NewTraceIDInterceptorFor creates an interceptor that uses a custom header name