How the client works
You do not need to understand every internal layer before you use ReactorSDK, but it helps to know what the client is already doing for you. This page explains the moving parts behind a normal ReactorSDK::Client so debugging and day-to-day use feel less mysterious.
If you only want to get a request working, read Quickstart first and come back here later.
Client composition
When you initialize the client, the SDK validates configuration and then builds infrastructure in a fixed order.
| Attribute | Description |
|---|---|
| Configuration | Stores constructor options and validates required credentials immediately. |
| Authentication | Fetches and refreshes Adobe IMS access tokens using OAuth server-to-server. |
| RateLimiter | Enforces a per-client token bucket so requests stay within Adobe's documented request budget. |
| Connection | Wraps Faraday, injects headers, performs retries, and raises typed SDK errors. |
| Paginator | Follows cursor-based pagination and always returns complete collections. |
| ResponseParser | Converts JSON:API response hashes into typed Ruby resource objects. |
All endpoint groups, such as properties, rules, libraries, and revisions, are then instantiated with those shared dependencies.
Connection behavior
The Connection object centralizes outbound Reactor API behavior so endpoint classes can stay focused on paths, payloads, and return types.
Responsibilities
- Inject
Authorization,x-api-key,x-gw-ims-org-id, andAcceptheaders. - Apply the shared rate limiter before every request.
- Retry transient failure statuses with backoff and jitter.
- Normalize
204 No Contentresponses tonil. - Parse JSON responses and raise typed errors for non-success statuses.
Important defaults
| Setting | Value |
|---|---|
| Base URL | https://reactor.adobe.io |
| Accept header | application/vnd.api+json;revision=1 |
| Content type | application/vnd.api+json |
| Timeout | 30 seconds |
| Open timeout | 10 seconds |
| Retry statuses | 429, 500, 502, 503, 504 |
Pagination by default
Cursor pagination is one of the most important implementation details in ReactorSDK. Adobe list endpoints can silently truncate your result set if you request only the first page. The SDK avoids that by always routing list calls through the paginator.
The paginator requests page[size]=100, follows links.next until it
disappears, and returns a single flat array. This means list methods are
complete-collection methods by default, not page methods.
List methods are fully paginated
# PR123 = property ID.
# LB123 = library ID.
# Each call automatically walks all pages until Adobe stops returning links.next.
rules = client.rules.list_for_property("PR123")
libraries = client.libraries.list_for_property("PR123")
builds = client.builds.list_for_library("LB123")
Rate limiting and retries
The SDK models Adobe's documented limit of 120 requests per minute per access token with a token bucket limiter. One limiter is created per ReactorSDK::Client, which means multiple client instances do not share rate limit state.
- The bucket starts full, so the first burst of requests can proceed immediately.
- When tokens run low, callers block until enough time has elapsed for the next token.
- Separate client instances keep credentials, rate-limit state, and token caches isolated.
Retries are handled at the Faraday layer. Application code usually only needs business-level retry logic, such as retrying a background job later or polling for a build result.
Parsing and typed endpoints
The endpoint layer is intentionally thin because most shared behavior is centralized. Endpoint classes inherit payload helpers from BaseEndpoint, then call shared helpers such as fetch_resource, list_resources, create_resource, and update_resource.
That is why the public API reads consistently:
Predictable endpoint style
# Fetch one property by Adobe property ID.
client.properties.find("PR123")
# List all rules that belong to a property.
client.rules.list_for_property("PR123")
# Create a new library inside a property.
client.libraries.create(property_id: "PR123", name: "Release 1.0")
# Upload a zipped extension package from disk.
client.extension_packages.create(package_path: "tmp/my_extension.zip")
The parser uses a type registry for heterogeneous results like search responses, and it has special handling for revision lookups where the full entity snapshot appears in the JSON:API included array.