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 JSON 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(:json)
    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)