Class: Sendly::Client

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

Overview

Main Sendly API client

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, api_key: nil, base_url: nil, timeout: 30, max_retries: 3, organization_id: nil) ⇒ Client

Create a new Sendly client.

Two calling conventions are supported (both produce the same client):

# Positional (matches Sendly's published code samples and the
# idiom of most other Ruby HTTP SDKs):
client = Sendly::Client.new("sk_live_v1_xxx")
client = Sendly::Client.new("sk_live_v1_xxx", timeout: 60)

# Keyword (existing v3.30.0 signature):
client = Sendly::Client.new(api_key: "sk_live_v1_xxx")

Parameters:

  • api_key (String, nil) (defaults to: nil)

    Your Sendly API key (also accepted as positional)

  • base_url (String, nil) (defaults to: nil)

    API base URL (optional)

  • timeout (Integer) (defaults to: 30)

    Request timeout in seconds (default: 30)

  • max_retries (Integer) (defaults to: 3)

    Maximum retry attempts (default: 3)

  • organization_id (String, nil) (defaults to: nil)

    Organization ID (optional)



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/sendly/client.rb', line 43

def initialize(*args, api_key: nil, base_url: nil, timeout: 30, max_retries: 3, organization_id: nil)
  # Backward-compatible positional API key. Previously this constructor
  # only accepted `api_key:` as a keyword; every code sample in our
  # docs used positional, breaking copy-paste for new users.
  if !args.empty?
    raise ArgumentError, "Sendly::Client.new accepts at most one positional argument (api_key)" if args.length > 1
    raise ArgumentError, "Cannot pass api_key both positionally and as keyword" unless api_key.nil?
    api_key = args.first
  end

  @api_key = api_key
  @base_url = (base_url || Sendly.base_url).chomp("/")
  @timeout = timeout
  @max_retries = max_retries
  @organization_id = organization_id || ENV["SENDLY_ORG_ID"]

  validate_api_key!
end

Instance Attribute Details

#api_keyString (readonly)

Returns API key.

Returns:

  • (String)

    API key



12
13
14
# File 'lib/sendly/client.rb', line 12

def api_key
  @api_key
end

#base_urlString (readonly)

Returns Base URL.

Returns:

  • (String)

    Base URL



15
16
17
# File 'lib/sendly/client.rb', line 15

def base_url
  @base_url
end

#max_retriesInteger (readonly)

Returns Maximum retry attempts.

Returns:

  • (Integer)

    Maximum retry attempts



21
22
23
# File 'lib/sendly/client.rb', line 21

def max_retries
  @max_retries
end

#organization_idString?

Returns Organization ID.

Returns:

  • (String, nil)

    Organization ID



24
25
26
# File 'lib/sendly/client.rb', line 24

def organization_id
  @organization_id
end

#timeoutInteger (readonly)

Returns Request timeout in seconds.

Returns:

  • (Integer)

    Request timeout in seconds



18
19
20
# File 'lib/sendly/client.rb', line 18

def timeout
  @timeout
end

Instance Method Details

#accountSendly::AccountResource

Access the Account resource



79
80
81
# File 'lib/sendly/client.rb', line 79

def 
  @account ||= AccountResource.new(self)
end

#business_upgradeSendly::BusinessUpgradeResource

Access the Business Upgrade resource (entity-upgrade flow)



156
157
158
# File 'lib/sendly/client.rb', line 156

def business_upgrade
  @business_upgrade ||= BusinessUpgradeResource.new(self)
end

#campaignsSendly::CampaignsResource

Access the Campaigns resource



107
108
109
# File 'lib/sendly/client.rb', line 107

def campaigns
  @campaigns ||= CampaignsResource.new(self)
end

#contactsSendly::ContactsResource

Access the Contacts resource



114
115
116
# File 'lib/sendly/client.rb', line 114

def contacts
  @contacts ||= ContactsResource.new(self)
end

#conversationsSendly::ConversationsResource

Access the Conversations resource



121
122
123
# File 'lib/sendly/client.rb', line 121

def conversations
  @conversations ||= ConversationsResource.new(self)
end

#delete(path) ⇒ Hash

Make a DELETE request

Parameters:

  • path (String)

    API path

Returns:

  • (Hash)

    Response body



221
222
223
# File 'lib/sendly/client.rb', line 221

def delete(path)
  request(:delete, path)
end

#draftsSendly::DraftsResource

Access the Drafts resource



135
136
137
# File 'lib/sendly/client.rb', line 135

def drafts
  @drafts ||= DraftsResource.new(self)
end

#enterpriseSendly::EnterpriseResource

Access the Enterprise resource



149
150
151
# File 'lib/sendly/client.rb', line 149

def enterprise
  @enterprise ||= EnterpriseResource.new(self)
end

#get(path, params = {}) ⇒ Hash

Make a GET request

Parameters:

  • path (String)

    API path

  • params (Hash) (defaults to: {})

    Query parameters

Returns:

  • (Hash)

    Response body



186
187
188
# File 'lib/sendly/client.rb', line 186

def get(path, params = {})
  request(:get, path, params: params)
end

#get_unversioned(path, params = {}) ⇒ Hash

Make a GET request against the API origin, bypassing the /api/v1 base. Used by resources whose endpoints live at the origin (e.g. the URL shortener at /api/links).

Parameters:

  • path (String)

    Origin-relative path (e.g. "/api/links")

  • params (Hash) (defaults to: {})

    Query parameters

Returns:

  • (Hash)

    Response body



232
233
234
# File 'lib/sendly/client.rb', line 232

def get_unversioned(path, params = {})
  request(:get, path, params: params, unversioned: true)
end

#labelsSendly::LabelsResource

Access the Labels resource



128
129
130
# File 'lib/sendly/client.rb', line 128

def labels
  @labels ||= LabelsResource.new(self)
end

Access the Links resource (branded URL shortening)



177
178
179
# File 'lib/sendly/client.rb', line 177

def links
  @links ||= LinksResource.new(self)
end

#mediaSendly::Media

Access the Media resource

Returns:



100
101
102
# File 'lib/sendly/client.rb', line 100

def media
  @media ||= Media.new(self)
end

#messagesSendly::Messages

Access the Messages resource

Returns:



65
66
67
# File 'lib/sendly/client.rb', line 65

def messages
  @messages ||= Messages.new(self)
end

#numbersSendly::NumbersResource

Access the Numbers resource



163
164
165
# File 'lib/sendly/client.rb', line 163

def numbers
  @numbers ||= NumbersResource.new(self)
end

#patch(path, body = {}) ⇒ Hash

Make a PATCH request

Parameters:

  • path (String)

    API path

  • body (Hash) (defaults to: {})

    Request body

Returns:

  • (Hash)

    Response body



204
205
206
# File 'lib/sendly/client.rb', line 204

def patch(path, body = {})
  request(:patch, path, body: body)
end

#patch_unversioned(path, body = {}) ⇒ Hash

Make a PATCH request against the API origin, bypassing the /api/v1 base.

Parameters:

  • path (String)

    Origin-relative path (e.g. "/api/links/:code")

  • body (Hash) (defaults to: {})

    Request body

Returns:

  • (Hash)

    Response body



250
251
252
# File 'lib/sendly/client.rb', line 250

def patch_unversioned(path, body = {})
  request(:patch, path, body: body, unversioned: true)
end

#post(path, body = {}) ⇒ Hash

Make a POST request

Parameters:

  • path (String)

    API path

  • body (Hash) (defaults to: {})

    Request body

Returns:

  • (Hash)

    Response body



195
196
197
# File 'lib/sendly/client.rb', line 195

def post(path, body = {})
  request(:post, path, body: body)
end

#post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg") ⇒ Hash

Make a multipart POST request for file uploads

Parameters:

  • path (String)

    API path

  • file (String, IO)

    File path or IO object

  • content_type (String) (defaults to: "image/jpeg")

    MIME type of the file

  • filename (String) (defaults to: "upload.jpg")

    Name for the uploaded file

Returns:

  • (Hash)

    Response body



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/sendly/client.rb', line 261

def post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg")
  uri = build_uri(path, {})
  http = build_http(uri)

  boundary = "SendlyRuby#{SecureRandom.hex(16)}"

  file_data = file.is_a?(String) ? File.binread(file) : file.read

  body = []
  body << "--#{boundary}\r\n"
  body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}\"\r\n"
  body << "Content-Type: #{content_type}\r\n\r\n"
  body << file_data
  body << "\r\n--#{boundary}--\r\n"

  req = Net::HTTP::Post.new(uri)
  req["Authorization"] = "Bearer #{api_key}"
  req["Accept"] = "application/json"
  req["User-Agent"] = "sendly-ruby/#{VERSION}"
  req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
  req["X-Organization-Id"] = @organization_id if @organization_id
  req.body = body.join

  attempt = 0
  begin
    response = http.request(req)
    handle_response(response)
  rescue Net::OpenTimeout, Net::ReadTimeout
    raise TimeoutError, "Request timed out after #{timeout} seconds"
  rescue Errno::ECONNREFUSED, Errno::ECONNRESET, SocketError => e
    raise NetworkError, "Connection failed: #{e.message}"
  rescue RateLimitError => e
    attempt += 1
    if attempt <= max_retries && e.retry_after
      sleep(e.retry_after)
      retry
    end
    raise
  rescue ServerError => e
    attempt += 1
    if attempt <= max_retries
      sleep(2 ** attempt)
      retry
    end
    raise
  end
end

#post_unversioned(path, body = {}) ⇒ Hash

Make a POST request against the API origin, bypassing the /api/v1 base.

Parameters:

  • path (String)

    Origin-relative path (e.g. "/api/links")

  • body (Hash) (defaults to: {})

    Request body

Returns:

  • (Hash)

    Response body



241
242
243
# File 'lib/sendly/client.rb', line 241

def post_unversioned(path, body = {})
  request(:post, path, body: body, unversioned: true)
end

#put(path, body = {}) ⇒ Hash

Make a PUT request

Parameters:

  • path (String)

    API path

  • body (Hash) (defaults to: {})

    Request body

Returns:

  • (Hash)

    Response body



213
214
215
# File 'lib/sendly/client.rb', line 213

def put(path, body = {})
  request(:put, path, body: body)
end

#rulesSendly::RulesResource

Access the Rules resource



142
143
144
# File 'lib/sendly/client.rb', line 142

def rules
  @rules ||= RulesResource.new(self)
end

#templatesSendly::TemplatesResource

Access the Templates resource



93
94
95
# File 'lib/sendly/client.rb', line 93

def templates
  @templates ||= TemplatesResource.new(self)
end

#ten_dlcSendly::TenDlcResource

Access the 10DLC resource



170
171
172
# File 'lib/sendly/client.rb', line 170

def ten_dlc
  @ten_dlc ||= TenDlcResource.new(self)
end

#verifySendly::VerifyResource

Access the Verify resource



86
87
88
# File 'lib/sendly/client.rb', line 86

def verify
  @verify ||= VerifyResource.new(self)
end

#webhooksSendly::WebhooksResource

Access the Webhooks resource



72
73
74
# File 'lib/sendly/client.rb', line 72

def webhooks
  @webhooks ||= WebhooksResource.new(self)
end