relay

package
v1.1.30 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package relay turns an upstream ThreatWinds service's failed HTTP response into the *catcher.SdkError a *relaying* service answers its own client with: the upstream's status becomes this service's status, its severity this service's severity, and its occurrence id this failure's id.

Why this is not in utils

utils.DoReq reads the same response into a *utils.RemoteError, which is a plain error precisely so that a caller's own `catcher.Error("calling X failed", err, args)` keeps the caller's message, args and status while still inheriting the upstream's occurrence id. That is what almost every caller wants, and it needs nothing from catcher — which is why utils imports nothing from catcher, and why binaries that only fetch a file (the ETL modules, through entities) do not link gin, protobuf and mongo-driver's bson just to make an HTTP request, or inherit catcher's stdout-writing goroutine at init.

Relaying is the rarer, opt-in decision, and it is the one that genuinely needs an *SdkError. It lives here so the cost lands on the callers that make that choice — services that already have gin linked because they serve HTTP — and on nobody else.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SdkErrorFromResponse

func SdkErrorFromResponse(resp *http.Response) *catcher.SdkError

SdkErrorFromResponse turns a failed HTTP response into a *catcher.SdkError, reading only the status line and the error headers catcher.GinError sets on the way out of a ThreatWinds service:

x-error-id → ErrorID (and Args["error_id"]), adopted so one failure keeps
             a single id across every service that touches it — but only
             when it is a well-formed UUID, see utils.RemoteError.ID.
             Absent or malformed → the id utils minted for this response,
             so the failure is identified exactly once either way.
x-error    → Cause, the remote's own rendered error text, bounded by utils
             to its maximum detail size. Absent → "unknown cause", the same
             text catcher itself uses.
status     → Severity, via calcSeverityFromStatus, and — clamped by
             relayStatus — Args["status"] (an int, as everywhere else in
             the SDK).

Args["status"] is the status a *relaying* handler will answer its own client with, since that is the key catcher.GinError reads. Using this function is therefore a decision to pass the upstream's status through: an upstream 401 becomes your client's 401. Most callers do not want that (their client's credentials are not the ones that were rejected) and should let catcher.Error/catcher.New build an error with their own args["status"] around the *utils.RemoteError DoReq returns — which still inherits the occurrence id.

Relaying a status < 500 also relays detail: catcher.SecureString returns the full Error() text — Cause and Args included — for anything under 500, and Cause here is the upstream's own message. That is SecureString's deliberate design (a client error is explained to the client), but the explanation now comes from a service the client never called, so relay a 4xx only when the upstream's text is genuinely about the caller's request.

It never touches resp.Body: the body may already have been consumed, may be nil on a hand-built response, and is the caller's to read and to close.

The error is built with catcher.New, not catcher.Error, so nothing is logged inside a transport helper — the error is logged once, wherever the caller ends up handling it (or automatically, if it reaches catcher.GinError).

Msg is the constant remoteErrorMessage and never the upstream's text; see that constant's doc for the two invariants that depend on it. Code follows from Msg: it identifies the error's type (an md5 of the message, per catcher.SdkError's field doc) and is therefore the same for every error this package builds, while the per-occurrence, greppable id is ErrorID. Conflating the two is precisely the drift catcher.GinError was fixed to remove.

A nil response, a nil Header map and absent headers are all handled: a nil response is reported as a 500, since "no response at all" is a local failure and 500 is the status catcher would otherwise default to.

Types

This section is empty.

Jump to

Keyboard shortcuts

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