Go
The Go SDK is an idiomatic, context-aware client emitted from the same GlottoIR as every
other target. It ships as a buildable Go module with a go.mod, so go get then construct a
client and call methods.
Quickstart
go get github.com/your-org/petstore
github.com/your-org/petstore is a placeholder: replace it with the generated module path for
your SDK.
ctx := context.Background()
client := petstore.NewClient(petstore.WithToken(os.Getenv("PETSTORE_TOKEN")))
// a single call
pet, err := client.Pets.CreatePet(ctx, &petstore.NewPet{Name: "Rex"})
if err != nil {
return err
}
// Pull iteration stops fetching immediately when the loop ends.
for pet, err := range client.Pets.ListPetsIter(ctx) {
if err != nil {
return err
}
fmt.Println(pet.Name)
}
Context-aware methods
Every method takes a context.Context first argument — client.Pets.CreatePet(ctx, body) — so
cancellation, deadlines, and request-scoped values flow through the call the idiomatic Go way.
Pagination
Use the Iter companion to range over typed values and errors. It fetches on demand; breaking the
loop releases its work before returning. The original <-chan Result[T] methods remain available,
but callers must cancel their context when abandoning a channel. See Pagination.
Manual Page companions fetch one typed page at a time. Response() decodes the full wrapper without another request, and NextPage() retains request options. See manual pagination.
Retries & backoff
Per-call RequestOption values override headers, timeouts, retry counts and idempotency. Methods without an existing option slot expose compatible WithOptions companions. See request options and defaults.
Transient failures (5xx, 429, transport errors) retry with exponential backoff and jitter;
the policy is configurable per client and honors the request context’s deadline. See
Retries & timeouts.
SSE streaming
Server-sent-event endpoints return a typed event stream decoded from the text/event-stream
framing. Their Iter companions close the response on a range-loop break; NDJSON endpoints use
the same pull API. Establishment shares buffered retry, idempotency and telemetry policy.
WithRequestTimeout bounds each opening attempt through the first body byte, then stops.
The context or an explicit WithStreamTimeout can bound the established stream. WebSocket
connectors also expose a WithContext companion; HTTP 101 ends their opening timeout. See Streaming.
Webhooks
Use the standalone VerifyWebhook helper in your HTTP handler to verify an inbound delivery’s
raw body before trusting it. See Webhooks.
Polling
Pollable operations receive a Poll<Method> companion, and WaitUntil covers custom predicates;
both respect context cancellation and deadlines. See Polling.
Telemetry
Pass WithHooks(&TelemetryHooks{…}) when constructing the client to observe requests, responses,
errors, and retries for your logs, metrics, or traces. See Telemetry hooks.
Typed errors
Non-2xx responses return typed error values carrying the parsed error body; use errors.As
to narrow to the concrete type rather than matching on status codes. See Errors.
Unknown response fields
Your API can add a response field without it being a breaking change — but a closed Go struct
would drop it, and encoding/json discards what it doesn’t recognize. The generated models keep
it instead: a field the SDK wasn’t generated from is retained on decode, readable through
ExtraFields(), and written back out when the model is re-serialized.
pet, _ := client.Pets.CreatePet(ctx, body)
// A field your API started returning after this SDK was generated.
if raw, ok := pet.ExtraFields()["species"]; ok {
var species string
_ = json.Unmarshal(raw, &species)
}
// Re-encoding preserves it — a read-modify-write never silently drops it.
body, _ := json.Marshal(pet)
ExtraFields() returns map[string]json.RawMessage, so nested objects and arrays survive intact,
and retention is recursive: a nested model keeps its own unknown fields. A payload whose fields
are all known encodes exactly as before, declared-field order included.
The accessor returns a snapshot: changing its map or json.RawMessage bytes does not change the
model or a later request. To send a field your spec does not model yet, use the per-call extra-body
escape hatch.
Updating retained timestamps
A timestamp the native time.Time carrier cannot represent remains available through
RetainedTemporal() and survives re-encoding. Assigning a valid *time.Time to the typed field
sends your replacement. Use the generated Set<Field>(value *time.Time) method to update both
the field and retained state; passing nil explicitly sends JSON null, including for an optional
field. For example, a timestamp field named At has SetAt(nil) unless that method name needs
a collision suffix. The method’s generated documentation gives its exact spelling.
A normal struct copy preserves untouched retained values. Calling a timestamp setter on that copy leaves the original’s retained state unchanged. Assigning nil directly leaves the existing retained wire value available, so use the setter when you intend to clear it.
Binary downloads
Binary endpoints return an owned BinaryResponse with response metadata. ReadAll(limit) bounds delivered bytes; WriteTo copies to an io.Writer. Both close the response. Close it explicitly after abandoning incremental reads. Mixed JSON/binary operations expose an explicit result branch. See file transfers.
File uploads
multipart/form-data operations assemble the body with a mime/multipart.Writer for you, and an
application/octet-stream body is sent raw — so binary uploads work without hand-building the
multipart payload.