http

package
v2.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 2, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package http provides an HTTP client wrapper for the MarketData SDK.

Index

Constants

View Source
const DefaultPoolSize = 50

DefaultPoolSize is the SDK's global concurrency pool size (ADR-014): NewClient's semaphore channel is sized to this, and this same constant backs the pool-saturation test, so a change to one is a change to both — a test asserting the wrong number silently (see T-5 in the deep review) can no longer happen.

Variables

This section is empty.

Functions

func PathSegment

func PathSegment(s string) string

PathSegment percent-encodes a caller-supplied value for safe use as a single URL path segment. It prevents path injection: a value such as "AAPL/../user" cannot escape its segment or re-route the request. Dot-segments ("." and ".."), which percent-encoding leaves intact because dots are unreserved, are neutralized explicitly.

func Version

func Version() string

Version returns the SDK version detected from Go module metadata. Falls back to "unknown" if build info is unavailable.

Types

type Client

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

Client wraps http.Client with SDK-specific functionality.

func New

func New(cfg Config) *Client

New creates a new HTTP client with the given configuration.

func (*Client) CloseIdleConnections

func (c *Client) CloseIdleConnections()

CloseIdleConnections closes any idle HTTP connections on the transport the SDK built for itself. It is a no-op when the underlying *http.Client was supplied via WithHTTPClient: that transport (and its connection pool) is intentionally shared with the caller, so closing its idle connections here would reach outside the SDK and affect the caller's own in-flight or pooled requests on that same client.

func (*Client) Do

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

Do executes the request with retry logic.

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string, params url.Values, result any) (*Response, error)

Get executes a GET request and decodes the JSON response, logging any terminal failure at ERROR (see logTerminalFailure).

func (*Client) GetFormatted

func (c *Client) GetFormatted(ctx context.Context, path string, params url.Values, format string) (*Response, error)

GetFormatted executes a GET request asking for a non-JSON wire format (format=csv or format=html, see ADR-018) and returns the raw response body as-is — no JSON decoding. Logs any terminal failure at ERROR (see logTerminalFailure), same as Get.

Unlike Get, this has no NoData concept: the API's own "no data" body shape is not consistent between JSON (404, a typed no-data body) and these formats (verified live: the same no-data condition on a CSV-formatted candles request comes back 200 with a degenerate body, not 404) — so 404/204 are passed through like any other status rather than specially interpreted. The caller gets whatever text came back.

func (*Client) GetUnversioned

func (c *Client) GetUnversioned(ctx context.Context, path string, params url.Values, result any) (*Response, error)

GetUnversioned executes a GET request without API version prefix. Used for endpoints like /status/ that are not versioned. Logs any terminal failure at ERROR (see logTerminalFailure).

func (*Client) GetUnversionedSilent

func (c *Client) GetUnversionedSilent(ctx context.Context, path string, params url.Values, result any) (*Response, error)

GetUnversionedSilent is [GetUnversioned] without the ERROR log on failure. Reserved for best-effort background priming (rate-limit state at startup) whose caller already discards the error by design — logging it there would either be pure noise or duplicate an ERROR already logged by a synchronous call to the same endpoint moments earlier.

func (*Client) SetDebug

func (c *Client) SetDebug(enabled bool)

SetDebug enables or disables emission of per-request debug records at runtime. It is safe for concurrent use with in-flight requests.

func (*Client) StatusProbe

func (c *Client) StatusProbe(ctx context.Context) (bool, error)

StatusProbe issues a minimal direct GET against the unversioned /status/ endpoint and reports whether the API answered as online (200 or 203). It deliberately bypasses the concurrency pool, retry loop, and rate-limit accounting: the offline-gate's background probe must stay responsive precisely when the pool is saturated or requests are failing, and must not pollute credit accounting.

type ColumnRequirer

type ColumnRequirer interface {
	RequiredColumns() []string
}

ColumnRequirer is implemented by a wire-response type whose decode needs a column the caller's "columns" filter may have dropped.

The rule is narrow on purpose. WithColumns promises that "missing columns simply decode as zero values", and for a data field that is exactly what happens — a filtered-out bid reads as 0. One column per response type is different: the array the conversion takes its row count from. Drop that one and every row disappears, so a present, billed quote is reported as not found. That is not a zero value, it is a wrong answer, and it is the same failure mode as the dropped "s" envelope — a field the decoder needs and the caller never thought to ask for.

Implementations return nil when they have no such column. Every wire response type implements it, which TestEveryWireResponseDeclaresRequiredColumns enforces as new ones are added.

type Config

type Config struct {
	HTTPClient       *http.Client
	BaseURL          string
	APIVersion       string
	Token            string
	Timeout          time.Duration
	ConnTimeout      time.Duration
	RetryCfg         retry.Config
	RateLimits       *ratelimit.Tracker
	Logger           *slog.Logger
	Debug            bool
	DemoMode         bool
	Sem              chan struct{}
	DefaultParams    url.Values
	FormatOnlyParams url.Values    // universal default params (from env vars / client config)
	StatusCache      *status.Cache // API status cache for retry decisions
	MaxRespBytes     int64         // cap on response body size (0 = default)
}

Config holds the HTTP client configuration.

type Request

type Request struct {
	Method      string
	Path        string
	Params      url.Values
	Headers     map[string]string
	Unversioned bool // If true, don't prefix with API version

	// RawFormat marks a request whose body is handed back verbatim (the
	// CSV/HTML facets, see ADR-018) rather than decoded. It exists so
	// decoder-serving adjustments — the "columns" repair below — apply only
	// where something actually decodes.
	RawFormat bool

	// RequiredColumns names the response columns this request's decoder
	// cannot do without, on top of the "s" envelope. Get fills it from the
	// destination value; see ColumnRequirer.
	RequiredColumns []string
}

Request represents an API request.

type Response

type Response struct {
	Raw        *http.Response // the raw HTTP response (body already consumed)
	StatusCode int
	Headers    http.Header
	Body       []byte
	RequestID  string
}

Response represents an API response.

func (*Response) StatusError

func (r *Response) StatusError(status string) error

StatusError builds the sdkerrors.APIError every service raises when a 200 response carries a body whose own "s" field is not "ok" — the one failure mode the >=400 mapping in parseAPIError cannot see. Every such guard is identical apart from the status string, so they share this method rather than repeating the same SupportContext call at each of the service call sites. A guard that genuinely needs a different exception type still calls Response.SupportContext directly.

func (*Response) SupportContext

func (r *Response) SupportContext(message, exceptionType string) sdkerrors.SupportContext

SupportContext builds a sdkerrors.SupportContext for an error tied to this response, filling RequestID, RequestURL, StatusCode, and Timestamp from the response itself so callers only need to supply the message and exception type. Used for errors raised outside the >=400 status mapping in parseAPIError — e.g. an HTTP 200 whose body reports its own failure.

RequestURL goes through wireURL like the >=400 and ParseError blocks do. It used to report Raw.Request.URL.Path, so all fifteen StatusError sites produced a support block stripped of the query — and Quote is served by bulkquotes, which addresses by query, so the block for a failed Quote(ctx, "AAPL") did not even say which symbol was asked for. A block exists to be pasted into a ticket, and this is the error class where the merged universal parameters matter most: a 200 whose body reports its own failure is the one most likely to have been caused by them.

Jump to

Keyboard shortcuts

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