core

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package core implements the HTTP machinery shared by every resource package. Decomposed into one concern per file: URL building, header building, send, retry policy, response parsing, and telemetry. Internal package — users cannot import it.

Index

Constants

View Source
const EnvVarAPIKey = "THREECOMMON_API_KEY"

EnvVarAPIKey is the environment variable consulted when threecommon.Config.APIKey is empty.

Variables

This section is empty.

Functions

func BuildHeaders

func BuildHeaders(in HeadersInput) http.Header

BuildHeaders returns a fresh http.Header populated with every header the SDK sends on every request.

func BuildURL

func BuildURL(baseURL, apiPath, path string, query map[string]string) string

BuildURL concatenates baseURL + apiPath + path and appends a query string. Pure function; no I/O. Trailing slashes on baseURL are trimmed; missing leading slashes on path are added.

Query values are stable-sorted by key for deterministic output.

func ComputeBackoff

func ComputeBackoff(attempt int, retryAfter time.Duration, policy RetryPolicy) time.Duration

ComputeBackoff returns the next sleep duration. When retryAfter is non-zero (e.g. parsed from a Retry-After header) it takes precedence, capped at policy.Max. Otherwise: exponential 2^attempt * Initial, capped at Max, with optional full-jitter randomization.

func IsIdempotent

func IsIdempotent(method string, hasIdempotencyKey bool) bool

IsIdempotent reports whether the SDK may safely retry a request with the given method. Caller-supplied idempotency keys upgrade non-idempotent methods.

func IsRetryableStatus

func IsRetryableStatus(status int) bool

IsRetryableStatus reports whether status is one we should retry on alongside method idempotency.

func ParseErrorBody

func ParseErrorBody(bodyText string) (code, message string, details map[string]any)

ParseErrorBody returns the parsed code, message, and details from the standard {"error": {...}} response shape. Returns zero values when the body can't be parsed.

func ParseRetryAfter

func ParseRetryAfter(header string) time.Duration

ParseRetryAfter parses a Retry-After header value. Accepts either delta-seconds or an HTTP-date. Returns 0 for missing, malformed, or already-elapsed values.

func ParseSuccessBody

func ParseSuccessBody(r *Response, out any) error

ParseSuccessBody decodes a 2xx body into out. Empty or non-JSON bodies are silently ignored — out keeps its zero value. Returns a JSON error only when the body looks like JSON but is malformed.

Types

type Client

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

Client orchestrates URL building → header building → send → parse → error mapping → retry. One instance per github.com/3-Common/sdk/sdk-go/client.API.

func NewClient

func NewClient(opts ClientOptions) *Client

NewClient constructs a *Client. Defaults Sleep and Now when omitted.

func NewFromConfig

func NewFromConfig(cfg threecommon.Config) (*Client, error)

NewFromConfig validates a threecommon.Config, fills in defaults, and returns a ready-to-use *Client. Resource packages and the [client] aggregator both call this so the entire SDK shares one validation path.

func (*Client) Do

func (c *Client) Do(ctx context.Context, req Request) error

Do execute a Request honoring the client's retry policy. Returns a typed error from the threecommon package on failure. ctx is checked between retries; cancellation propagates immediately.

type ClientOptions

type ClientOptions struct {
	APIKey     string
	BaseURL    string
	APIVersion string
	SDKVersion string
	Timeout    time.Duration
	Retry      RetryPolicy
	HTTPClient *http.Client
	Telemetry  *Telemetry
	Logger     threecommon.Logger
	NowFunc    func() time.Time                                 // injectable for tests
	SleepFunc  func(ctx context.Context, d time.Duration) error // injectable for tests
}

ClientOptions configures a *Client.

type HeadersInput

type HeadersInput struct {
	APIKey          string
	APIVersion      string
	SDKVersion      string
	UserAgentSuffix string
	TelemetryHeader string // "" omits the header
	IdempotencyKey  string // "" omits the header
	HasBody         bool   // false omits Content-Type (bodyless requests)
}

HeadersInput captures everything BuildHeaders needs to populate a request's header map. Pre-resolved by the caller so this stays a pure function.

type Request

type Request struct {
	Method         string
	Path           string
	Query          map[string]string
	Body           any
	Out            any           // pointer to decode 2xx body into
	IdempotencyKey string        // optional
	Timeout        time.Duration // overrides ClientOptions.Timeout when non-zero
	MaxRetries     int           // overrides ClientOptions.Retry.MaxRetries when non-zero (use -1 for "no retries")
}

Request describes one logical SDK call. The httpclient handles URL building, retries, and error mapping; the caller supplies path, method, query, and body.

type Response

type Response struct {
	Status    int
	Header    http.Header
	BodyText  string
	RequestID string
}

Response is a fully-buffered, post-read normalization of *http.Response. Headers are kept as the canonical http.Header map; the body is read once into a string and never read again from the underlying response. Callers must not pass the wrapped *http.Response back to the network.

func ReadResponse

func ReadResponse(resp *http.Response) (*Response, error)

ReadResponse drains response body and returns a Response. The original *http.Response body is closed before this returns.

func Send

func Send(ctx context.Context, in SendInput) (*Response, error)

Send issues a single HTTP request and returns a fully-buffered Response. The supplied ctx and Input.Timeout combine: whichever fires first cancels the request. Send does not retry; that is the caller's responsibility.

type RetryPolicy

type RetryPolicy struct {
	MaxRetries int
	Initial    time.Duration
	Max        time.Duration
	Jitter     bool
}

RetryPolicy mirrors threecommon.RetryDelay plus a max-attempts cap.

type SendInput

type SendInput struct {
	HTTPClient *http.Client
	URL        string
	Method     string
	Headers    http.Header
	Body       any           // marshaled to JSON when non-nil
	Timeout    time.Duration // 0 disables the per-request timeout
}

SendInput captures everything Send needs. Pre-built so Send stays a thin wrapper around the standard library — no header building, no URL building, no retry logic.

type Telemetry

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

Telemetry tracks one previous-request snapshot per client and emits the Threecommon-Client-Telemetry header value for the next request. Goroutine- safe — the snapshot is updated under a mutex because every field is read together.

func NewTelemetry

func NewTelemetry(enabled bool) *Telemetry

NewTelemetry returns a *Telemetry in the given enabled state.

func TelemetryFromClient

func TelemetryFromClient(c *Client) *Telemetry

TelemetryFromClient returns the *Telemetry behind a *Client so the aggregator package can implement github.com/3-Common/sdk/sdk-go/client.API.DisableTelemetry.

func (*Telemetry) Disable

func (t *Telemetry) Disable()

Disable turns telemetry off and clears the cached snapshot.

func (*Telemetry) Enabled

func (t *Telemetry) Enabled() bool

Enabled reports whether the next Telemetry.HeaderValue call will emit a header.

func (*Telemetry) HeaderValue

func (t *Telemetry) HeaderValue(sdkVersion, apiVersion string) string

HeaderValue returns the JSON value for the Threecommon-Client-Telemetry header on the next request. The empty string means "do not send the header".

func (*Telemetry) Record

func (t *Telemetry) Record(method, path string, status int, duration time.Duration)

Record stores a snapshot of the just-completed request. No-op when disabled.

Jump to

Keyboard shortcuts

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