Snippets
Minimal copy-paste blocks for flags, configs, kill switches and metric tracking.
Minimal copy-paste blocks, grouped by the registry taxonomy. These are the same leaves the docs get op returns.
release
release / flags
Read the new_checkout gate for the bound user. Assumes Configure() ran at startup — see Installation.
Read a flag
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetFlag(name) — name is the gate key; returns false if the gate is
// absent, disabled, or killswitched (never a user argument — it's bound).
if c.GetFlag("new_checkout") {
// new behaviour
}Flag with an explicit fallback
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetFlagOr(name, def) — def is returned ONLY when the flag can't be
// evaluated (engine not ready, or the gate is absent); a gate that
// evaluates false returns false.
on := c.GetFlagOr("new_checkout", true) // name; def returned only on can't-evaluate
_ = onrelease / configs
Read the billing_copy dynamic config (typed JSON value). Assumes Configure() ran at startup — see Installation.
Read a config
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetConfig(name) — name is the config key; returns (value any, ok bool).
// ok is false when the key is absent. Type-assert value to what you stored.
if cfg, ok := c.GetConfig("billing_copy"); ok {
m := cfg.(map[string]any) // configs are arbitrary JSON
_ = m["cta"]
}Config with an explicit fallback
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetConfigOr(name, def) — def is returned when the key is absent.
v := c.GetConfigOr("billing_copy", map[string]any{"cta": "Buy"}) // name; def
_ = vrelease / killswitches
Check whether the payments kill switch is engaged. Assumes Configure() ran at startup — see Installation.
Read a kill switch
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetKillswitch(name) — name is the kill-switch key; true means engaged
// (the feature is killed). Returns false if the switch is absent.
if c.GetKillswitch("payments") {
// feature is killed — short-circuit
}Read a named per-key switch
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetKillswitch(name, switchKey) — the optional switchKey selects a named
// per-key override (the dashboard "switches" feature). When that key has no
// override, it falls back to the kill switch's top-level value.
if c.GetKillswitch("payments", "eu") {
// killed for the "eu" variant
}metrics
metrics / track
Track a metric/conversion event from the bound Client. Metrics in the dashboard
are computed from these events. Assumes Configure() ran at startup — see
Installation.
Track an event
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// Track(event, props)
// event — the event your metric is built on (required)
// props — optional payload; numeric/string fields you can sum/filter on in a
// metric (private attributes are stripped before egress)
c.Track("checkout_started", map[string]any{"amount": 49, "currency": "usd"})Fire-and-forget (never blocks your response) and a no-op under
ConfigureForTesting / ConfigureForOffline. The unit is the bound user
(user_id, else anonymous_id); with no unit the call is a no-op.
Track without properties
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
c.Track("checkout_started", nil) // props are optional — pass nilops
ops / see
Report a caught, handled error (or a non-exception "violation") to Shipeasy with
See() — fire-and-forget, never panics into the request path. Package-level, so
it reports against the configuration from Configure. Assumes Configure() ran
at startup — see Installation.
Report a handled error
if err := charge(order); err != nil {
// CausesThe(subject) — what the error affects (e.g. "checkout")
// To(outcome) — the terminal: what you do about it; builds + fires once
shipeasy.See(err).CausesThe("checkout").To("use the backup processor")
fallbackCharge(order)
}Attach context inline on .To(outcome, extras)
if err := charge(order); err != nil {
// .To(outcome, extras) — PREFERRED. The extras map is merged like a final
// .Extras() call (later map wins). Structured fields are sanitized
// (string/number/bool only; private attributes stripped before egress).
// The consequence sentence stays whole and there is no ordering to remember.
shipeasy.See(err).
CausesThe("checkout").
To("use cached prices", map[string]any{"order_id": order.ID})
}.To returns nothing, so extras cannot trail the terminal in Go — the inline
form above is how you attach them. And never wedge .Extras(...) between
.CausesThe and .To: it splits the consequence sentence in half and is hard
to read.
// NEVER — the subject and the outcome must stay adjacent:
// shipeasy.See(err).CausesThe("checkout").Extras(m).To("use cached prices")Report a non-exception violation
// A bad state that isn't an error — the name is a STABLE fingerprint; put
// variable data in .Extras, never the name. .To() is the terminal.
shipeasy.SeeViolation("missing_invoice").
CausesThe("billing").
To("skip the dunning email")Mark an expected error — report NOTHING
if errors.Is(err, sql.ErrNoRows) {
// transmits nothing; .Because(...) / .Extras() are local-debug only
shipeasy.ControlFlowException(err).Because("a missing row is the empty-state path")
}