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

#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



193
194
195
# File 'lib/sendly/client.rb', line 193

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



158
159
160
# File 'lib/sendly/client.rb', line 158

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

#labelsSendly::LabelsResource

Access the Labels resource



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

def labels
  @labels ||= LabelsResource.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

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

Make a PATCH request

Parameters:

  • path (String)

    API path

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

    Request body

Returns:

  • (Hash)

    Response body



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

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

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

Make a POST request

Parameters:

  • path (String)

    API path

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

    Request body

Returns:

  • (Hash)

    Response body



167
168
169
# File 'lib/sendly/client.rb', line 167

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



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/sendly/client.rb', line 204

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

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

Make a PUT request

Parameters:

  • path (String)

    API path

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

    Request body

Returns:

  • (Hash)

    Response body



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

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

#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