Ruby
A guide to using Soxom-generated Ruby SDKs. The generated gem targets Ruby
3.1+, ships idiomatic classes with YARD documentation, and verifies webhook
signatures with constant-time comparison. The module name is the
PascalCase of the gem name; the examples below assume a gem named
acme_sdk (module AcmeSdk).
Installation
Section titled “Installation”The gem name is whatever you set in targets.ruby.gem_name. Add it to your
Gemfile:
gem "acme_sdk"bundle install# orgem install acme_sdkQuickstart
Section titled “Quickstart”require "acme_sdk"
# Credentials are read from the matching env var when the option is omitted.client = AcmeSdk::Client.new(api_key: ENV["ACME_SDK_API_KEY"])
user = client.users.get("user-123")puts user.emailConfiguration
Section titled “Configuration”Configure globally and reuse a shared client, or construct per-client:
AcmeSdk.configure do |config| config.api_key = ENV["ACME_SDK_API_KEY"] config.base_url = "https://api.acme.com" config.timeout = 60 # seconds; read/total timeout config.open_timeout = 30 # seconds; connection timeout config.max_retries = 3 config.logger = Logger.new($stdout)end
client = AcmeSdk.client# Per-client overrides take precedence over the global config:client = AcmeSdk::Client.new(api_key: "...", timeout: 10)Authentication
Section titled “Authentication”The constructor option and the env-var name are derived from the SDK’s
configured auth scheme. <PREFIX> below is the upcased gem name (e.g.
acme_sdk → ACME_SDK).
Bearer token
Section titled “Bearer token”# Sent as `Authorization: Bearer <token>`client = AcmeSdk::Client.new(api_key: ENV["ACME_SDK_API_KEY"])API key (header, query, or cookie)
Section titled “API key (header, query, or cookie)”client = AcmeSdk::Client.new(api_key: ENV["ACME_SDK_API_KEY"])The injection location is fixed at generation time from the OpenAPI security scheme.
OAuth2 client credentials
Section titled “OAuth2 client credentials”client = AcmeSdk::Client.new( auth: AcmeSdk::Auth::ClientCredentialsSource.new( token_url: "https://auth.acme.com/oauth/token", client_id: ENV["ACME_CLIENT_ID"], client_secret: ENV["ACME_CLIENT_SECRET"], scopes: %w[read write] ))The token is fetched lazily on the first request, cached until shortly before
expiry, and refreshed automatically; a 401 triggers a single forced refresh
and retry.
Making requests
Section titled “Making requests”Operations are mounted under resource and subresource namespaces as configured
in soxom.yaml:
client.users.listclient.users.get("user-123")client.users.settings.update("user-123", theme: "dark")Pagination
Section titled “Pagination”List endpoints return an auto-paginating enumerator — iterate it and the SDK fetches each page transparently:
client.users.list.each { |user| puts user.email } # walks every page
client.users.list.lazy.first(50) # bounded — stops earlyBoth cursor and offset schemes are supported, selected by
pagination.default_type in soxom.yaml.
Streaming
Section titled “Streaming”Operations marked streaming return an enumerator over Server-Sent Events,
parsed lazily from the response body:
client.chat.completions.create( model: "gpt-4", messages: [{ role: "user", content: "Hello" }], stream: true).each do |event| print event.choices.first.delta.contentendErrors
Section titled “Errors”Every error descends from AcmeSdk::Errors::Error, so a single rescue catches
anything from the SDK. The hierarchy:
AcmeSdk::Errors::Error├── ConfigurationError├── APIError│ ├── BadRequestError (400)│ ├── AuthenticationError (401)│ ├── PermissionError (403)│ ├── NotFoundError (404)│ ├── ConflictError (409)│ ├── UnprocessableEntityError (422)│ ├── RateLimitError (429)│ └── ServerError (5xx)├── ConnectionError├── DeserializationError└── SignatureVerificationErrorbegin client.users.get("user-123")rescue AcmeSdk::Errors::RateLimitError => e sleep(e.retry_after || 30) retryrescue AcmeSdk::Errors::AuthenticationError # refresh token / re-authenticaterescue AcmeSdk::Errors::APIError => e warn "API error #{e.http_status}: #{e.message} (request id: #{e.request_id})"endEvery APIError carries #http_status, #code, #message, #request_id,
#response_body, and #errors.
Retries
Section titled “Retries”GET, HEAD, OPTIONS, and DELETE are retried automatically on connection
errors and on HTTP 5xx, 408, and 429, with exponential backoff and
jitter. POST, PATCH, and PUT retry only when an Idempotency-Key header
is set — the SDK auto-injects one via SecureRandom.uuid for those methods. A
parseable Retry-After header is always honored. Tune the budget with
config.max_retries.
Webhooks
Section titled “Webhooks”When your OpenAPI 3.1 spec declares top-level webhooks, the SDK emits a
typed parser with signature verification:
event = AcmeSdk::Webhooks.parse( payload: request.raw_post, signature: request.headers["X-Signature"], secret: ENV["WEBHOOK_SECRET"])
case eventwhen AcmeSdk::Webhooks::UserCreatedEvent provision(event.data)endWebhooks.verify_signature uses OpenSSL.fixed_length_secure_compare for
constant-time comparison, with a default tolerance of 300 seconds.
Logging & instrumentation
Section titled “Logging & instrumentation”Pass any Logger-compatible object via config.logger; the SDK redacts known
secret keys from emitted logs. When ActiveSupport::Notifications is available
in the host app, the SDK publishes a request.<gem_name> event per HTTP
exchange for instrumentation.
Configuration in soxom.yaml
Section titled “Configuration in soxom.yaml”targets: ruby: gem_name: "acme_sdk" # RubyGems name; default is snake_case of sdk.name generator_version: "0.1.0" # pin the generator versionSee the soxom.yaml reference for the complete option list.
Supported Ruby versions
Section titled “Supported Ruby versions”- Ruby 3.1, 3.2, 3.3, 3.4
Build & publish
Section titled “Build & publish”bundle installgem build acme_sdk.gemspecgem push acme_sdk-<version>.gem