Ruby
The Ruby SDK is an idiomatic gem emitted from the same GlottoIR as every other target. It uses
snake_case methods, keyword args, immutable Data.define models with from_json, and YARD doc
comments generated from the operation prose in the spec.
Manual pages expose items, response metadata and explicit next_page navigation. Per-call request_options: controls headers, deadlines, retries, extra parameters and cancellation. Binary operations return an owned BinaryDownload with bounded read_all, pipe, response metadata and close; block iteration releases the response on break or error. See pagination, request retries and controls, streaming, and file transfers.
Quickstart
gem install petstore
require 'petstore'
client = Petstore::Client.new(token: '<token>')
result = client.pets.get(pet_id: '...')
puts result
Resource objects
Operations are methods on resource objects — client.pets.get(id), client.pets.photos.add(...) —
the Stripe-Ruby service-accessor shape, rather than flat methods on Client.
Persistent connections
Requests reuse a persistent per-host connection (via net-http-persistent) instead of opening a
fresh socket per call, so throughput holds up under load and across threads.
Typed errors
Non-2xx responses raise ApiError, a StandardError hierarchy carrying the parsed, typed error
body, so you rescue RateLimitError rather than inspecting status codes. Discriminated-union
bodies resolve to the right variant. See Errors.
Pagination
List methods return an Enumerator that walks every page lazily, advancing the cursor for you.
See Pagination.
Retries & backoff
Transient failures (5xx, 429, transport errors) retry with exponential backoff and jitter,
configurable per client. See Retries & timeouts, Streaming,
and Authentication.
Unknown response fields
Your API can add a response field without it being a breaking change — but a generated Data class has only the members it declares, and its from_json factory reads only those. The generated
models keep it instead: a field the SDK wasn’t generated from is retained on decode, readable
through an accessor, and written back out when the model is re-serialized.
pet = client.pets.create_pet(body)
# A field your API started returning after this SDK was generated.
species = pet.extra_fields["species"]
# Re-encoding preserves it — a read-modify-write never silently drops it.
json = JSON.generate(pet.to_h)
extra_fields returns a frozen Hash, so nested objects and arrays survive intact, and retention
is recursive.
Use pet.with(name: "Rex") to create an updated immutable value. The copy keeps unknown
response fields and retained timestamps for members you did not change. Replacing a timestamp
explicitly replaces its retained wire value too.
If a declared member already uses with, the copy helper uses the first free name starting
with with_2, preserving the member’s reader.
The retained fields are held in an instance variable rather than as a Data member, so
members, inspect, == and pattern matching on your models are all unchanged — and both
Pet.new(id: …) and Pet.new('p1', …) still work.
The retained fields are read-only by design. To send a field your spec doesn’t model yet, use the per-call extra-body escape hatch rather than writing to the retained bag.
Missing and null fields
By default an optional member that decodes from JSON null is nil, the same as an omitted key,
and to_h drops it — so a read-modify-write sends a decoded null back as an absent key. Set
targets.ruby.model_presence: explicit to keep missing, null
and a value apart: a missing member holds your SDK module’s frozen MISSING singleton and nil
means JSON null. Code that treated nil as absence must change; the generated
MODEL_PRESENCE.md shows the idioms.