Class: D4H::API::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/d4h/api/client.rb

Overview

Public: HTTP client for the D4H Developer API v3.

Wraps a Faraday connection with Bearer token authentication and provides accessor methods for every supported API resource.

The client builds URL paths as ‘v3/#context/#context_id/resource`, where context is typically “team” but can be “organisation” for organisation-scoped endpoints.

Examples

# Discover your identity (no context needed)
client = D4H::API::Client.new(api_key: ENV.fetch("D4H_TOKEN"))
me = client.whoami.show

# Team context (default)
client = D4H::API::Client.new(
  api_key:    ENV.fetch("D4H_TOKEN"),
  context_id: 42,
)
client.member.list
client.event.show(id: 1)

# Organisation context
client = D4H::API::Client.new(
  api_key:    ENV.fetch("D4H_TOKEN"),
  context:    "organisation",
  context_id: 99,
)

Constant Summary collapse

DEFAULT_BASE_URL =

Internal: Default base URL for the D4H API. Override via D4H_BASE_URL env var or the base_url: constructor parameter.

"https://api.team-manager.us.d4h.com"
MAX_RETRIES =

Internal: Maximum number of retries for transient errors (429, 5xx).

3
RETRY_INTERVAL =

Internal: Base interval in seconds for exponential backoff.

1
MAX_RETRY_INTERVAL =

Internal: Maximum backoff interval in seconds.

30
RETRY_BACKOFF_FACTOR =

Internal: Backoff factor — each retry doubles the wait time.

2
RETRIABLE_STATUSES =

Internal: HTTP status codes that are transient and safe to retry.

[429, 500, 502, 503, 504].freeze
RETRIABLE_METHODS =

Internal: HTTP methods to retry. All methods are retriable for transient server errors since the request may not have been processed.

%i[delete get head options patch post put].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key:, context: "team", context_id: nil, base_url: ENV.fetch("D4H_BASE_URL", DEFAULT_BASE_URL), adapter: Faraday.default_adapter, max_retries: MAX_RETRIES, retry_interval: RETRY_INTERVAL) ⇒ Client

Public: Initialize a new D4H API client.

api_key: - A String Bearer token for API authentication. context: - The context scope, either “team” (default) or “organisation”. context_id: - The Integer ID of the team or organisation (optional;

required for all resources except whoami).

base_url: - The base URL for the D4H API. Defaults to D4H_BASE_URL env

var, or "https://api.team-manager.us.d4h.com" if unset.
Change this for EU or other regional endpoints.

adapter: - The Faraday adapter to use (default: Faraday.default_adapter).

Pass `[:test, stubs]` for testing with Faraday::Adapter::Test.

max_retries: - Integer number of retries for transient errors (default: 3).

Set to 0 to disable retries.

retry_interval: - Float base interval in seconds between retries (default: 1).

Set to 0 in tests to avoid sleeping.


62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/d4h/api/client.rb', line 62

def initialize(api_key:, context: "team", context_id: nil,
  base_url: ENV.fetch("D4H_BASE_URL", DEFAULT_BASE_URL),
  adapter: Faraday.default_adapter,
  max_retries: MAX_RETRIES, retry_interval: RETRY_INTERVAL)
  @api_key = api_key
  @base_url = base_url
  @context = context
  @context_id = context_id
  @adapter = adapter
  @max_retries = max_retries
  @retry_interval = retry_interval
end

Instance Attribute Details

#adapterObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def adapter
  @adapter
end

#api_keyObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def api_key
  @api_key
end

#base_urlObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def base_url
  @base_url
end

#contextObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def context
  @context
end

#context_idObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def context_id
  @context_id
end

#max_retriesObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def max_retries
  @max_retries
end

#retry_intervalObject (readonly)

Public: Returns the base URL, API token, Faraday adapter, context type, context ID, max retries, and retry interval.



45
46
47
# File 'lib/d4h/api/client.rb', line 45

def retry_interval
  @retry_interval
end

Instance Method Details

#animalObject

Animals



149
# File 'lib/d4h/api/client.rb', line 149

def animal = AnimalResource.new(self)

#animal_groupObject



150
# File 'lib/d4h/api/client.rb', line 150

def animal_group = AnimalGroupResource.new(self)

#animal_group_membershipObject



151
# File 'lib/d4h/api/client.rb', line 151

def animal_group_membership = AnimalGroupMembershipResource.new(self)

#animal_qualificationObject



152
# File 'lib/d4h/api/client.rb', line 152

def animal_qualification = AnimalQualificationResource.new(self)

#attendanceObject

Attendance



155
# File 'lib/d4h/api/client.rb', line 155

def attendance = AttendanceResource.new(self)

#base_pathObject

Public: Returns the versioned, context-scoped path prefix.

Examples

client.base_path  # => "v3/team/42"

Raises ArgumentError if context_id is nil.

Raises:

  • (ArgumentError)


82
83
84
85
86
# File 'lib/d4h/api/client.rb', line 82

def base_path
  raise ArgumentError, "context_id is required for this resource" if context_id.nil?

  "v3/#{context}/#{context_id}"
end

#connectionObject

Public: Returns the memoized Faraday connection.

Configured with URL-encoded request encoding, JSON response parsing, exponential backoff retry on transient errors, and the chosen adapter.

The retry middleware retries on 429 and 5xx status codes up to max_retries times with exponential backoff (1s, 2s, 4s) capped at 30s. It also respects the D4H API’s ratelimit headers for wait times. Set max_retries: 0 to disable retries.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/d4h/api/client.rb', line 116

def connection
  @connection ||= Faraday.new do |f|
    f.url_prefix = base_url
    f.request(:url_encoded)
    if max_retries > 0
      f.request(:retry,
        max: max_retries,
        interval: retry_interval,
        max_interval: MAX_RETRY_INTERVAL,
        backoff_factor: RETRY_BACKOFF_FACTOR,
        retry_statuses: RETRIABLE_STATUSES,
        methods: RETRIABLE_METHODS,
        retry_block: ->(env:, options:, retry_count:, exception:, will_retry_in:) {
          Kernel.warn("[D4H] Retry #{retry_count + 1}/#{options.max} for #{env[:method].upcase} " \
            "#{env[:url]} (#{exception.class}) in #{will_retry_in}s")
        })
    end
    f.response(:json, content_type: "application/json")
    f.adapter(*Array(adapter))
  end
end

#custom_fieldObject

Custom Fields



158
# File 'lib/d4h/api/client.rb', line 158

def custom_field = CustomFieldResource.new(self)

#custom_field_for_entityObject



159
# File 'lib/d4h/api/client.rb', line 159

def custom_field_for_entity = CustomFieldForEntityResource.new(self)

#customer_identifierObject

Operations & Organization



209
# File 'lib/d4h/api/client.rb', line 209

def customer_identifier = CustomerIdentifierResource.new(self)

#d4h_moduleObject



210
# File 'lib/d4h/api/client.rb', line 210

def d4h_module = D4hModuleResource.new(self)

#d4h_taskObject



211
# File 'lib/d4h/api/client.rb', line 211

def d4h_task = D4hTaskResource.new(self)

#documentObject

Documents



162
# File 'lib/d4h/api/client.rb', line 162

def document = DocumentResource.new(self)

#dutyObject



212
# File 'lib/d4h/api/client.rb', line 212

def duty = DutyResource.new(self)

#equipmentObject

Equipment



165
# File 'lib/d4h/api/client.rb', line 165

def equipment = EquipmentResource.new(self)

#equipment_brandObject



166
# File 'lib/d4h/api/client.rb', line 166

def equipment_brand = EquipmentBrandResource.new(self)

#equipment_categoryObject



167
# File 'lib/d4h/api/client.rb', line 167

def equipment_category = EquipmentCategoryResource.new(self)

#equipment_fundObject



168
# File 'lib/d4h/api/client.rb', line 168

def equipment_fund = EquipmentFundResource.new(self)

#equipment_inspectionObject



169
# File 'lib/d4h/api/client.rb', line 169

def equipment_inspection = EquipmentInspectionResource.new(self)

#equipment_inspection_resultObject



170
# File 'lib/d4h/api/client.rb', line 170

def equipment_inspection_result = EquipmentInspectionResultResource.new(self)

#equipment_inspection_stepObject



171
# File 'lib/d4h/api/client.rb', line 171

def equipment_inspection_step = EquipmentInspectionStepResource.new(self)

#equipment_inspection_step_resultObject



172
# File 'lib/d4h/api/client.rb', line 172

def equipment_inspection_step_result = EquipmentInspectionStepResultResource.new(self)

#equipment_kindObject



173
# File 'lib/d4h/api/client.rb', line 173

def equipment_kind = EquipmentKindResource.new(self)

#equipment_locationObject



174
# File 'lib/d4h/api/client.rb', line 174

def equipment_location = EquipmentLocationResource.new(self)

#equipment_modelObject



175
# File 'lib/d4h/api/client.rb', line 175

def equipment_model = EquipmentModelResource.new(self)

#equipment_retired_reasonObject



176
# File 'lib/d4h/api/client.rb', line 176

def equipment_retired_reason = EquipmentRetiredReasonResource.new(self)

#equipment_supplierObject



177
# File 'lib/d4h/api/client.rb', line 177

def equipment_supplier = EquipmentSupplierResource.new(self)

#equipment_supplier_refObject



178
# File 'lib/d4h/api/client.rb', line 178

def equipment_supplier_ref = EquipmentSupplierRefResource.new(self)

#equipment_usageObject



179
# File 'lib/d4h/api/client.rb', line 179

def equipment_usage = EquipmentUsageResource.new(self)

#eventObject

Events & Incidents



182
# File 'lib/d4h/api/client.rb', line 182

def event = EventResource.new(self)

#exerciseObject



183
# File 'lib/d4h/api/client.rb', line 183

def exercise = ExerciseResource.new(self)

#handler_groupObject

Handlers



190
# File 'lib/d4h/api/client.rb', line 190

def handler_group = HandlerGroupResource.new(self)

#handler_group_membershipObject



191
# File 'lib/d4h/api/client.rb', line 191

def handler_group_membership = HandlerGroupMembershipResource.new(self)

#handler_qualificationObject



192
# File 'lib/d4h/api/client.rb', line 192

def handler_qualification = HandlerQualificationResource.new(self)

#health_safety_categoryObject

Health & Safety



195
# File 'lib/d4h/api/client.rb', line 195

def health_safety_category = HealthSafetyCategoryResource.new(self)

#health_safety_reportObject



196
# File 'lib/d4h/api/client.rb', line 196

def health_safety_report = HealthSafetyReportResource.new(self)

#health_safety_severityObject



197
# File 'lib/d4h/api/client.rb', line 197

def health_safety_severity = HealthSafetySeverityResource.new(self)

#incidentObject



184
# File 'lib/d4h/api/client.rb', line 184

def incident = IncidentResource.new(self)

#incident_involved_injuryObject



185
# File 'lib/d4h/api/client.rb', line 185

def incident_involved_injury = IncidentInvolvedInjuryResource.new(self)

#incident_involved_metadataObject



186
# File 'lib/d4h/api/client.rb', line 186

def  = IncidentInvolvedMetadataResource.new(self)

#incident_involved_personObject



187
# File 'lib/d4h/api/client.rb', line 187

def incident_involved_person = IncidentInvolvedPersonResource.new(self)

#inspectObject

Public: Returns a short string representation that hides the API key.



139
140
141
# File 'lib/d4h/api/client.rb', line 139

def inspect
  "#<D4H::Client>"
end

#location_bookmarkObject



213
# File 'lib/d4h/api/client.rb', line 213

def location_bookmark = LocationBookmarkResource.new(self)

#memberObject

Members



200
# File 'lib/d4h/api/client.rb', line 200

def member = MemberResource.new(self)

#member_custom_statusObject



201
# File 'lib/d4h/api/client.rb', line 201

def member_custom_status = MemberCustomStatusResource.new(self)

#member_groupObject



202
# File 'lib/d4h/api/client.rb', line 202

def member_group = MemberGroupResource.new(self)

#member_group_membershipObject



203
# File 'lib/d4h/api/client.rb', line 203

def member_group_membership = MemberGroupMembershipResource.new(self)

#member_qualificationObject



204
# File 'lib/d4h/api/client.rb', line 204

def member_qualification = MemberQualificationResource.new(self)

#member_qualification_awardObject



205
# File 'lib/d4h/api/client.rb', line 205

def member_qualification_award = MemberQualificationAwardResource.new(self)

#member_retired_reasonObject



206
# File 'lib/d4h/api/client.rb', line 206

def member_retired_reason = MemberRetiredReasonResource.new(self)

#organisationObject



214
# File 'lib/d4h/api/client.rb', line 214

def organisation = OrganisationResource.new(self)

#repairObject



215
# File 'lib/d4h/api/client.rb', line 215

def repair = RepairResource.new(self)

#resource_bundleObject



216
# File 'lib/d4h/api/client.rb', line 216

def resource_bundle = ResourceBundleResource.new(self)

#roleObject



217
# File 'lib/d4h/api/client.rb', line 217

def role = RoleResource.new(self)

#searchObject



218
# File 'lib/d4h/api/client.rb', line 218

def search = SearchResultResource.new(self)

#tagObject



219
# File 'lib/d4h/api/client.rb', line 219

def tag = TagResource.new(self)

#teamObject



220
# File 'lib/d4h/api/client.rb', line 220

def team = TeamResource.new(self)

#whiteboardObject



221
# File 'lib/d4h/api/client.rb', line 221

def whiteboard = WhiteboardResource.new(self)

#whoamiObject



222
# File 'lib/d4h/api/client.rb', line 222

def whoami = WhoamiResource.new(self)