Class: Basecamp::Services::BaseService
- Inherits:
-
Object
- Object
- Basecamp::Services::BaseService
- Defined in:
- lib/basecamp/generated/services/base_service.rb
Overview
Base service class for Basecamp API services.
Provides shared functionality for all service classes including:
- HTTP method delegation (http_get, http_post, etc.)
- Path building helpers
- Pagination support
Direct Known Subclasses
AccountService, AttachmentsService, AuthorizationService, AutomationService, BookmarksService, BoostsService, CalendarsService, CampfiresService, CardColumnsService, CardStepsService, CardTablesService, CardsService, CheckinsService, ClientApprovalsService, ClientCorrespondencesService, ClientRepliesService, ClientVisibilityService, CloudFilesService, CommentsService, DocumentsService, DraftsService, EventsService, EverythingService, FoldersService, ForwardsService, GaugesService, GoogleDocumentsService, HillChartsService, LineupService, MessageBoardsService, MessageTypesService, MessagesService, MyAssignmentsService, MyNotesService, MyNotificationsService, PeopleService, ProjectsService, RecordingsService, ReportsService, SchedulesService, SearchService, SubscriptionsService, TemplatesService, TimelineService, TimesheetsService, TodolistGroupsService, TodolistsService, TodosService, TodosetsService, ToolsService, UploadsService, VaultsService, WebhooksService, WormholesService
Instance Attribute Summary collapse
-
#account_id ⇒ String
readonly
The account ID for API requests.
Instance Method Summary collapse
-
#bucket_path(project_id, path) ⇒ String
protected
Build a bucket (project) path.
-
#compact_params(**kwargs) ⇒ Hash
protected
Helper to remove nil values from a hash.
-
#compact_query_params(**kwargs) ⇒ Hash
protected
Like compact_params, but also drops empty arrays.
-
#http ⇒ HTTP
protected
The HTTP client for direct access.
- #http_delete(path) ⇒ Object protected
- #http_get(path, params: {}) ⇒ Object protected
- #http_post(path, body: nil) ⇒ Object protected
- #http_post_raw(path, body:, content_type:) ⇒ Object protected
- #http_put(path, body: nil) ⇒ Object protected
-
#http_put_multipart(path, io:, filename:, content_type:, field: "file") ⇒ Object
protected
Upload a file as multipart/form-data.
-
#initialize(client) ⇒ BaseService
constructor
A new instance of BaseService.
-
#safe_hook ⇒ Object
protected
Invoke a hook callback, swallowing exceptions so hooks never break SDK behavior.
-
#with_operation(service:, operation:, resource_type: nil, is_mutation: false, project_id: nil, resource_id: nil) { ... } ⇒ Object
protected
Wraps a service operation with hooks for observability.
-
#wrap_paginated(service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) ⇒ Object
protected
Wraps a paginated operation with hooks, preserving the pagination metadata carried by the inner ListEnumerator.
-
#wrap_paginated_wrapped(key:, service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) ⇒ Object
protected
Wraps a wrapped-paginated operation with hooks.
Constructor Details
#initialize(client) ⇒ BaseService
Returns a new instance of BaseService.
26 27 28 29 30 |
# File 'lib/basecamp/generated/services/base_service.rb', line 26 def initialize(client) @client = client @account_id = client.account_id @hooks = client.hooks end |
Instance Attribute Details
#account_id ⇒ String (readonly)
Returns the account ID for API requests.
23 24 25 |
# File 'lib/basecamp/generated/services/base_service.rb', line 23 def account_id @account_id end |
Instance Method Details
#bucket_path(project_id, path) ⇒ String (protected)
Build a bucket (project) path.
182 183 184 |
# File 'lib/basecamp/generated/services/base_service.rb', line 182 def bucket_path(project_id, path) "/buckets/#{project_id}#{path}" end |
#compact_params(**kwargs) ⇒ Hash (protected)
Helper to remove nil values from a hash.
161 162 163 |
# File 'lib/basecamp/generated/services/base_service.rb', line 161 def compact_params(**kwargs) kwargs.compact end |
#compact_query_params(**kwargs) ⇒ Hash (protected)
Like compact_params, but also drops empty arrays. For query filters an
empty array means "no filter" and must be omitted entirely: Faraday's
nested encoder would otherwise emit a bare bucket_ids[], which Rails
normalizes into a bogus [0] filter instead of the unfiltered request
the caller intended. Not used for request bodies, where an explicit
empty array (e.g. clearing a list) can be meaningful.
174 175 176 |
# File 'lib/basecamp/generated/services/base_service.rb', line 174 def compact_query_params(**kwargs) kwargs.reject { |_, value| value.nil? || value == [] } end |
#http ⇒ HTTP (protected)
Returns the HTTP client for direct access.
154 155 156 |
# File 'lib/basecamp/generated/services/base_service.rb', line 154 def http @client.http end |
#http_delete(path) ⇒ Object (protected)
200 201 202 203 204 |
# File 'lib/basecamp/generated/services/base_service.rb', line 200 %i[get post put delete post_raw put_raw].each do |method| define_method(:"http_#{method}") do |*args, **kwargs, &block| @client.public_send(method, *args, **kwargs, &block) end end |
#http_get(path, params: {}) ⇒ Object (protected)
200 201 202 203 204 |
# File 'lib/basecamp/generated/services/base_service.rb', line 200 %i[get post put delete post_raw put_raw].each do |method| define_method(:"http_#{method}") do |*args, **kwargs, &block| @client.public_send(method, *args, **kwargs, &block) end end |
#http_post(path, body: nil) ⇒ Object (protected)
200 201 202 203 204 |
# File 'lib/basecamp/generated/services/base_service.rb', line 200 %i[get post put delete post_raw put_raw].each do |method| define_method(:"http_#{method}") do |*args, **kwargs, &block| @client.public_send(method, *args, **kwargs, &block) end end |
#http_post_raw(path, body:, content_type:) ⇒ Object (protected)
200 201 202 203 204 |
# File 'lib/basecamp/generated/services/base_service.rb', line 200 %i[get post put delete post_raw put_raw].each do |method| define_method(:"http_#{method}") do |*args, **kwargs, &block| @client.public_send(method, *args, **kwargs, &block) end end |
#http_put(path, body: nil) ⇒ Object (protected)
200 201 202 203 204 |
# File 'lib/basecamp/generated/services/base_service.rb', line 200 %i[get post put delete post_raw put_raw].each do |method| define_method(:"http_#{method}") do |*args, **kwargs, &block| @client.public_send(method, *args, **kwargs, &block) end end |
#http_put_multipart(path, io:, filename:, content_type:, field: "file") ⇒ Object (protected)
Upload a file as multipart/form-data.
212 213 214 215 216 217 218 |
# File 'lib/basecamp/generated/services/base_service.rb', line 212 def http_put_multipart(path, io:, filename:, content_type:, field: "file") boundary = "BasecampSDK#{SecureRandom.hex(16)}" body = build_multipart_body(boundary: boundary, field: field, io: io, \ filename: filename, content_type: content_type) http_put_raw(path, body: body, content_type: "multipart/form-data; boundary=#{boundary}") nil end |
#safe_hook ⇒ Object (protected)
Invoke a hook callback, swallowing exceptions so hooks never break SDK behavior.
147 148 149 150 151 |
# File 'lib/basecamp/generated/services/base_service.rb', line 147 def safe_hook yield rescue => e warn "Basecamp hook error: #{e.class}: #{e.}" end |
#with_operation(service:, operation:, resource_type: nil, is_mutation: false, project_id: nil, resource_id: nil) { ... } ⇒ Object (protected)
Wraps a service operation with hooks for observability.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/basecamp/generated/services/base_service.rb', line 43 def with_operation(service:, operation:, resource_type: nil, is_mutation: false, project_id: nil, resource_id: nil) info = OperationInfo.new( service: service, operation: operation, resource_type: resource_type, is_mutation: is_mutation, project_id: project_id, resource_id: resource_id ) start = Process.clock_gettime(Process::CLOCK_MONOTONIC) safe_hook { @hooks.on_operation_start(info) } result = yield duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { @hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: nil)) } result rescue => e duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { @hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: e)) } raise end |
#wrap_paginated(service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) ⇒ Object (protected)
Wraps a paginated operation with hooks, preserving the pagination metadata carried by the inner ListEnumerator. Fires on_operation_start eagerly (paginate fetches page 1 inside the yield, so the start hook must precede it); on_operation_end fires via ensure when the first traversal completes, errors, or is cut short by break/take — exactly once, so re-enumerating never emits an on_operation_end without a matching start.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/basecamp/generated/services/base_service.rb', line 67 def wrap_paginated(service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) info = OperationInfo.new( service: service, operation: operation, is_mutation: is_mutation, project_id: project_id, resource_id: resource_id ) hooks = @hooks start = Process.clock_gettime(Process::CLOCK_MONOTONIC) safe_hook { hooks.on_operation_start(info) } begin enum = yield # paginate fetches page 1 here rescue => e duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: e)) } raise end ended = false ListEnumerator.new(enum.) do |yielder| error = nil begin enum.each { |item| yielder.yield(item) } rescue => e error = e raise ensure unless ended ended = true duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: error)) } end end end end |
#wrap_paginated_wrapped(key:, service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) ⇒ Object (protected)
Wraps a wrapped-paginated operation with hooks. Fires on_operation_start eagerly (before page 1 fetch), and on_operation_end exactly once, when the first traversal of the events Enumerator completes/errors/breaks.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/basecamp/generated/services/base_service.rb', line 106 def wrap_paginated_wrapped(key:, service:, operation:, is_mutation: false, project_id: nil, resource_id: nil) info = OperationInfo.new( service: service, operation: operation, is_mutation: is_mutation, project_id: project_id, resource_id: resource_id ) hooks = @hooks start = Process.clock_gettime(Process::CLOCK_MONOTONIC) safe_hook { hooks.on_operation_start(info) } begin result = yield # paginate_wrapped fetches page 1 here rescue => e duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: e)) } raise end inner_enum = result[key] ended = false wrapped_enum = ListEnumerator.new(inner_enum.) do |yielder| error = nil begin inner_enum.each { |item| yielder.yield(item) } rescue => e error = e raise ensure # Exactly once: on_operation_start fired once at call time, so # re-enumerating must not emit unmatched on_operation_end events. unless ended ended = true duration = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round safe_hook { hooks.on_operation_end(info, OperationResult.new(duration_ms: duration, error: error)) } end end end result.merge(key => wrapped_enum) end |