Class: Sendly::Client
- Inherits:
-
Object
- Object
- Sendly::Client
- Defined in:
- lib/sendly/client.rb
Overview
Main Sendly API client
Instance Attribute Summary collapse
-
#api_key ⇒ String
readonly
API key.
-
#base_url ⇒ String
readonly
Base URL.
-
#max_retries ⇒ Integer
readonly
Maximum retry attempts.
-
#organization_id ⇒ String?
Organization ID.
-
#timeout ⇒ Integer
readonly
Request timeout in seconds.
Instance Method Summary collapse
-
#account ⇒ Sendly::AccountResource
Access the Account resource.
-
#business_upgrade ⇒ Sendly::BusinessUpgradeResource
Access the Business Upgrade resource (entity-upgrade flow).
-
#campaigns ⇒ Sendly::CampaignsResource
Access the Campaigns resource.
-
#contacts ⇒ Sendly::ContactsResource
Access the Contacts resource.
-
#conversations ⇒ Sendly::ConversationsResource
Access the Conversations resource.
-
#delete(path) ⇒ Hash
Make a DELETE request.
-
#drafts ⇒ Sendly::DraftsResource
Access the Drafts resource.
-
#enterprise ⇒ Sendly::EnterpriseResource
Access the Enterprise resource.
-
#generate_idempotency_key ⇒ Object
Generate an idempotency key for a logical request.
-
#get(path, params = {}) ⇒ Hash
Make a GET request.
-
#get_unversioned(path, params = {}) ⇒ Hash
Make a GET request against the API origin, bypassing the
/api/v1base. -
#initialize(*args, api_key: nil, base_url: nil, timeout: 30, max_retries: 3, organization_id: nil) ⇒ Client
constructor
Create a new Sendly client.
-
#labels ⇒ Sendly::LabelsResource
Access the Labels resource.
-
#links ⇒ Sendly::LinksResource
Access the Links resource (branded URL shortening).
-
#media ⇒ Sendly::Media
Access the Media resource.
-
#messages ⇒ Sendly::Messages
Access the Messages resource.
-
#numbers ⇒ Sendly::NumbersResource
Access the Numbers resource.
-
#patch(path, body = {}) ⇒ Hash
Make a PATCH request.
-
#patch_unversioned(path, body = {}) ⇒ Hash
Make a PATCH request against the API origin, bypassing the
/api/v1base. -
#post(path, body = {}, idempotency_key: nil, auto_idempotency_key: true) ⇒ Hash
Make a POST request.
-
#post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg", idempotency_key: nil) ⇒ Hash
Make a multipart POST request for file uploads.
-
#post_unversioned(path, body = {}) ⇒ Hash
Make a POST request against the API origin, bypassing the
/api/v1base. -
#put(path, body = {}) ⇒ Hash
Make a PUT request.
-
#rcs ⇒ Sendly::RcsResource
Access the RCS resource.
-
#rules ⇒ Sendly::RulesResource
Access the Rules resource.
-
#templates ⇒ Sendly::TemplatesResource
Access the Templates resource.
-
#ten_dlc ⇒ Sendly::TenDlcResource
Access the 10DLC resource.
-
#verify ⇒ Sendly::VerifyResource
Access the Verify resource.
-
#webhooks ⇒ Sendly::WebhooksResource
Access the Webhooks resource.
-
#whatsapp ⇒ Sendly::WhatsAppResource
Access the WhatsApp resource.
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")
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_key ⇒ String (readonly)
Returns API key.
12 13 14 |
# File 'lib/sendly/client.rb', line 12 def api_key @api_key end |
#base_url ⇒ String (readonly)
Returns Base URL.
15 16 17 |
# File 'lib/sendly/client.rb', line 15 def base_url @base_url end |
#max_retries ⇒ Integer (readonly)
Returns Maximum retry attempts.
21 22 23 |
# File 'lib/sendly/client.rb', line 21 def max_retries @max_retries end |
#organization_id ⇒ String?
Returns Organization ID.
24 25 26 |
# File 'lib/sendly/client.rb', line 24 def organization_id @organization_id end |
#timeout ⇒ Integer (readonly)
Returns Request timeout in seconds.
18 19 20 |
# File 'lib/sendly/client.rb', line 18 def timeout @timeout end |
Instance Method Details
#account ⇒ Sendly::AccountResource
Access the Account resource
79 80 81 |
# File 'lib/sendly/client.rb', line 79 def account @account ||= AccountResource.new(self) end |
#business_upgrade ⇒ Sendly::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 |
#campaigns ⇒ Sendly::CampaignsResource
Access the Campaigns resource
107 108 109 |
# File 'lib/sendly/client.rb', line 107 def campaigns @campaigns ||= CampaignsResource.new(self) end |
#contacts ⇒ Sendly::ContactsResource
Access the Contacts resource
114 115 116 |
# File 'lib/sendly/client.rb', line 114 def contacts @contacts ||= ContactsResource.new(self) end |
#conversations ⇒ Sendly::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
245 246 247 |
# File 'lib/sendly/client.rb', line 245 def delete(path) request(:delete, path) end |
#drafts ⇒ Sendly::DraftsResource
Access the Drafts resource
135 136 137 |
# File 'lib/sendly/client.rb', line 135 def drafts @drafts ||= DraftsResource.new(self) end |
#enterprise ⇒ Sendly::EnterpriseResource
Access the Enterprise resource
149 150 151 |
# File 'lib/sendly/client.rb', line 149 def enterprise @enterprise ||= EnterpriseResource.new(self) end |
#generate_idempotency_key ⇒ Object
Generate an idempotency key for a logical request. Reused across retry attempts so the server can recognize a retry of a POST that already reached it and return the original result instead of executing again.
345 346 347 |
# File 'lib/sendly/client.rb', line 345 def generate_idempotency_key "sendly-ruby-retry-#{SecureRandom.uuid}" end |
#get(path, params = {}) ⇒ Hash
Make a GET request
200 201 202 |
# File 'lib/sendly/client.rb', line 200 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).
256 257 258 |
# File 'lib/sendly/client.rb', line 256 def get_unversioned(path, params = {}) request(:get, path, params: params, unversioned: true) end |
#labels ⇒ Sendly::LabelsResource
Access the Labels resource
128 129 130 |
# File 'lib/sendly/client.rb', line 128 def labels @labels ||= LabelsResource.new(self) end |
#links ⇒ Sendly::LinksResource
Access the Links resource (branded URL shortening)
177 178 179 |
# File 'lib/sendly/client.rb', line 177 def links @links ||= LinksResource.new(self) end |
#media ⇒ Sendly::Media
Access the Media resource
100 101 102 |
# File 'lib/sendly/client.rb', line 100 def media @media ||= Media.new(self) end |
#messages ⇒ Sendly::Messages
Access the Messages resource
65 66 67 |
# File 'lib/sendly/client.rb', line 65 def @messages ||= Messages.new(self) end |
#numbers ⇒ Sendly::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
228 229 230 |
# File 'lib/sendly/client.rb', line 228 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.
274 275 276 |
# File 'lib/sendly/client.rb', line 274 def patch_unversioned(path, body = {}) request(:patch, path, body: body, unversioned: true) end |
#post(path, body = {}, idempotency_key: nil, auto_idempotency_key: true) ⇒ Hash
Make a POST request
Every POST carries an Idempotency-Key header. By default the client
generates one per logical request ("sendly-ruby-retry-idempotency_key to
supply your own (1-255 printable ASCII characters) and extend that
protection across process restarts, or auto_idempotency_key: false
to skip auto-generation for endpoints that dedupe by other means.
218 219 220 221 |
# File 'lib/sendly/client.rb', line 218 def post(path, body = {}, idempotency_key: nil, auto_idempotency_key: true) request(:post, path, body: body, idempotency_key: idempotency_key, auto_idempotency_key: auto_idempotency_key) end |
#post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg", idempotency_key: nil) ⇒ Hash
Make a multipart POST request for file uploads
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/sendly/client.rb', line 286 def post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg", idempotency_key: nil) uri = build_uri(path, {}) http = build_http(uri) explicit_key = normalize_idempotency_key(idempotency_key) key = explicit_key || generate_idempotency_key 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 req["Idempotency-Key"] = key 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.}" 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 # A 5xx response may be cached under the key server-side, so an # auto-generated key is rotated to let the retry re-execute. # Caller-supplied keys are never rotated. key = generate_idempotency_key if explicit_key.nil? 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.
265 266 267 |
# File 'lib/sendly/client.rb', line 265 def post_unversioned(path, body = {}) request(:post, path, body: body, unversioned: true) end |
#put(path, body = {}) ⇒ Hash
Make a PUT request
237 238 239 |
# File 'lib/sendly/client.rb', line 237 def put(path, body = {}) request(:put, path, body: body) end |
#rcs ⇒ Sendly::RcsResource
Access the RCS resource
191 192 193 |
# File 'lib/sendly/client.rb', line 191 def rcs @rcs ||= RcsResource.new(self) end |
#rules ⇒ Sendly::RulesResource
Access the Rules resource
142 143 144 |
# File 'lib/sendly/client.rb', line 142 def rules @rules ||= RulesResource.new(self) end |
#templates ⇒ Sendly::TemplatesResource
Access the Templates resource
93 94 95 |
# File 'lib/sendly/client.rb', line 93 def templates @templates ||= TemplatesResource.new(self) end |
#ten_dlc ⇒ Sendly::TenDlcResource
Access the 10DLC resource
170 171 172 |
# File 'lib/sendly/client.rb', line 170 def ten_dlc @ten_dlc ||= TenDlcResource.new(self) end |
#verify ⇒ Sendly::VerifyResource
Access the Verify resource
86 87 88 |
# File 'lib/sendly/client.rb', line 86 def verify @verify ||= VerifyResource.new(self) end |
#webhooks ⇒ Sendly::WebhooksResource
Access the Webhooks resource
72 73 74 |
# File 'lib/sendly/client.rb', line 72 def webhooks @webhooks ||= WebhooksResource.new(self) end |
#whatsapp ⇒ Sendly::WhatsAppResource
Access the WhatsApp resource
184 185 186 |
# File 'lib/sendly/client.rb', line 184 def whatsapp @whatsapp ||= WhatsAppResource.new(self) end |