Package contract
The planned gem is nordic_devhouse and the top-level module is NordicDevhouse. It provides small immutable result objects and a reusable connection-pooled client.
| Distribution | Namespace or import | Runtime |
|---|---|---|
| nordic_devhouse | NordicDevhouse | Supported Ruby release lines |
Create and reuse the client
The Ruby interface favors keyword arguments and explicit result objects. One run call hides job polling and retry details without converting responses into loosely structured hashes.
require "nordic_devhouse"
client = NordicDevhouse::Client.new(
api_key: ENV.fetch("NORDIC_DEVHOUSE_API_KEY"),
timeout: 30,
max_retries: 3
)
result = client.scrape.run(
url: "https://example.com/products",
formats: [:json],
idempotency_key: "catalog-2026-08-11"
)
puts [result.job_id, result.records].join(" ")Control a durable job
Start and wait fit Sidekiq, Active Job, and other worker systems without coupling the core gem to them. Fiber scheduling may be supported by the transport implementation.
job = client.scrape.start(
url: "https://example.com/products",
formats: [:json]
)
result = client.jobs.wait(
job.id,
timeout: 600
)Public models
Names follow the language conventions, but every SDK preserves the same fields and job-state semantics.
| Concept | Contract |
|---|---|
| Client options | API key, base URL, request timeout, retry budget, and optional test transport |
| Scrape request | URL, output formats, webhook URL, metadata, and idempotency key |
| Job | Stable ID, status, timestamps, progress, and warnings |
| Job result | Job ID, record count, typed data, metadata, and request ID |
| Webhook event | Verified event ID, type, timestamp, and typed data |
Handle errors idiomatically
All exceptions inherit NordicDevhouse::Error and expose code, request_id, status, attempts, and cause. RateLimited adds retry_after and ValidationError adds issues.
begin
client.scrape.run(url: url, formats: [:json])
rescue NordicDevhouse::RateLimited => error
logger.warn("rate limited",
request_id: error.request_id,
retry_after: error.retry_after)
raise
rescue NordicDevhouse::ValidationError => error
render_validation(error.issues)
rescue NordicDevhouse::Error => error
logger.error("SDK failure", request_id: error.request_id)
raise
endVerify the raw webhook body
Verification uses the exact request bytes, validates HMAC-SHA256 and timestamp tolerance, and returns a typed event. Persist the verified event ID to prevent duplicate processing.
event = client.webhooks.verify(
payload: request.raw_post,
signature: request.get_header("HTTP_NORDIC_SIGNATURE"),
secret: ENV.fetch("NORDIC_WEBHOOK_SECRET")
)
import_result(event.data.job_id) if event.type == "scrape.completed"Runtime and lifecycle rules
- 1Support maintained Ruby release lines and publish typed RBS declarations
- 2Use keyword arguments at the caller seam
- 3Return immutable value objects instead of OpenStruct values
- 4Reuse pooled connections and make close idempotent
- 5Keep Rails and Sidekiq helpers in optional integration files