Skip to content

Commit a4cea66

Browse files
authored
feat: add failover to messages (#327)
1 parent 5d07837 commit a4cea66

File tree

18 files changed

+544
-15
lines changed

18 files changed

+544
-15
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 7.30.0
2+
3+
* Implements the Failover feature in Messages API. [#327](https://github.com/Vonage/vonage-ruby-sdk/pull/327)
4+
15
# 7.29.1
26

37
* Fixes a bug with the Viber Service Messages API channel. [#323](https://github.com/Vonage/vonage-ruby-sdk/pull/323)

README.md

Lines changed: 133 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,26 +341,151 @@ client.applications.list(auto_advance: false)
341341

342342
The [Vonage Messages API](https://developer.vonage.com/messages/overview) allows you to send messages over a number of different channels, and various message types within each channel. See the Vonage Developer Documentation for a [complete API reference](https://developer.vonage.com/en/api/messages) listing all the channel and message type combinations.
343343

344-
The Ruby SDK allows you to construct message data for specific messaging channels. Other than SMS (which has only one type -- text), you need to pass the message `:type` as well as the `:message` itself as arguments to the appropriate messages method, along with any optional properties if needed.
344+
### Sending a Message
345+
346+
The Ruby SDK implements a `Messaging` object which can be accessed via a `messaging` method on the `Client` object. The `Messaging` object has a `send` method which lets you send any message type via any channel.
347+
348+
```ruby
349+
response = client.messaging.send(
350+
# message data
351+
)
352+
```
353+
354+
There are a number of ways in which you can pass the necessary message data to the method.
355+
356+
**Using Keyword Arguments**
357+
358+
You can pass the message properties and their values as keyword arguments to the method. For example:
359+
360+
```ruby
361+
response = client.messaging.send(
362+
to: '447700900000',
363+
from: '447700900001',
364+
channel: 'sms',
365+
message_type: 'text',
366+
text: 'Hello world!'
367+
)
368+
```
369+
370+
**Spread a Hash**
371+
372+
For more complex message structures, you can define the message as a Hash literal and then spread that Hash as keyword arguments by passing it to the `send` method using the double-splat opertator (`**`). For example:
345373

346374
```ruby
347-
# creating an SMS message
348-
message = Vonage::Messaging::Message.sms(message: 'Hello world!')
375+
message = {
376+
to: '447700900000',
377+
from: '447700900001',
378+
channel: 'mms',
379+
message_type: 'image',
380+
image: {
381+
url: 'https://example.com/image.jpg',
382+
caption: 'This is an image'
383+
}
384+
}
385+
386+
response = client.messaging.send(**message)
387+
```
388+
389+
**Using a Combination of Keyword Arguments and Spread**
390+
391+
You can use a combination of the above two approaches. This might be useful in situations where you want to iteratively send the same message to multiple recipients, for example:
392+
393+
```ruby
394+
message = {
395+
from: '447700900000',
396+
channel: 'sms',
397+
message_type: 'text',
398+
text: 'Hello world!'
399+
}
400+
401+
['447700900001', '447700900002', '447700900003'].each do |to_number|
402+
client.messaging.send(to: to_number, **message)
403+
end
404+
```
405+
406+
**Using Channel Convenience Methods**
407+
408+
The Ruby SDK provides convenience methods for each channel which return a Hash object which you can then pass to the `send` method in the same way that you would with a Hash literal. As well as a simpler interface, the convenience methods also provide some basic validation.
409+
410+
Other than SMS (which has only one type -- `text`), these methods require a `:type` argument, which defines the `message_type` of the message within that channel. They also require a `:message` argument, which defvines the message itself; this is a String in the case of `text` messages, and a Hash containing the appopriate properties for other message types (e.g. `image`). You can also optionally pass an `opts` arguments, the value of which should be a Hash which defines any other property that you want to include in the message.
411+
412+
```ruby
413+
# Using the SMS method like this:
414+
message = client.messaging.sms(to: "447700900000", from: "447700900001", message: "Hello world!")
415+
416+
# is the equivalent of using a Hash literal like this:
417+
message = {
418+
channel: "sms",
419+
to: "447700900000",
420+
from: "447700900001",
421+
message_type: "text",
422+
text: "Hello world!"
423+
}
424+
```
425+
426+
Once the message Hash is created, you can then pass it into the `send` method using the double-splat opertator (`**`).
427+
428+
```ruby
429+
response = client.messaging.send(**message)
430+
```
431+
432+
A few additional examples of using these convenience methods are shown below:
433+
434+
435+
```ruby
436+
# creating an RCS Text message
437+
message = client.messaging.rcs(to: "447700900000", from: "RCS-Agent", type: 'text', message: 'Hello world!')
349438
350439
# creating a WhatsApp Text message
351-
message = Vonage::Messaging::Message.whatsapp(type: 'text', message: 'Hello world!')
440+
message = client.messaging.whatsapp(to: "447700900000", from: "447700900001", type: 'text', message: 'Hello world!')
352441
353442
# creating a WhatsApp Image message
354-
message = Vonage::Messaging::Message.whatsapp(type: 'image', message: { url: 'https://example.com/image.jpg' })
443+
message = client.messaging.whatsapp(to: "447700900000", from: "447700900001", type: 'image', message: { url: 'https://example.com/image.jpg' })
355444
356445
# creating an MMS audio message with optional properties
357-
message = Vonage::Messaging::Message.mms(type: 'audio', message: { url: 'https://example.com/audio.mp3' }, opts: {client_ref: "abc123"})
446+
message = client.messaging.mms(
447+
to: "447700900000",
448+
from: "447700900001",
449+
type: 'audio',
450+
message: {
451+
url: 'https://example.com/audio.mp3'
452+
},
453+
opts: {
454+
client_ref: "abc123"
455+
}
456+
)
457+
```
458+
459+
You can choose to omit the `to` and/or `from` arguments from the convenience method calls and instead pass them in as keyword arguments during the `send` method invocation.
460+
461+
```ruby
462+
message = client.messaging.sms(from: "447700900001", message: "Hello world!")
463+
464+
['447700900001', '447700900002', '447700900003'].each do |to_number|
465+
client.messaging.send(to: to_number, **message)
466+
end
358467
```
359468

360-
Once the message data is created, you can then send the message.
469+
### Sending a Message with Failover
470+
471+
The Messages API lets you define one or more failover messages which will be sent if the initial message is rejected. In the Ruby SDK, this feature is implemented by passing a `failover` keyword argument during the invocation of the `send` method. The value of this argument must be an Array containing one or more Hash objects representing the failover message(s). For example:
361472

362473
```ruby
363-
response = client.messaging.send(to: "447700900000", from: "447700900001", **message)
474+
# Sending an RCS message with failover to SMS
475+
rcs_message = messaging.rcs(
476+
to: '447900000000',
477+
from: 'RCS-Agent',
478+
type: 'text',
479+
message: 'This is an RCS message. If you see this, RCS is working!'
480+
)
481+
482+
sms_message = messaging.sms(
483+
to: '447900000000',
484+
from: 'Vonage',
485+
message: 'This is a failover SMS message in case RCS fails.'
486+
)
487+
488+
response = messaging.send(**rcs_message, failover: [sms_message])
364489
```
365490

366491
## Verify API v2

lib/vonage/messaging.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,17 @@ class Messaging < Namespace
2727
#
2828
# @see https://developer.vonage.com/api/messages#SendMessage
2929
#
30-
def send(to:, from:, **message)
31-
request('/v1/messages', params: {to: to, from: from, **message}, type: Post)
30+
def send(to:, from:, channel:, message_type:, failover: nil, **message)
31+
params = { to: to, from: from, channel: channel, message_type: message_type }.merge(message)
32+
33+
if failover
34+
raise ArgumentError.new("`failover` must be an array") unless failover.is_a?(Array)
35+
raise ArgumentError.new("`failover` must not be empty") if failover.empty?
36+
raise ArgumentError.new("`failover` must contain only Hashes") unless failover.all?(Hash)
37+
params[:failover] = failover
38+
end
39+
40+
request('/v1/messages', params: params, type: Post)
3241
end
3342

3443
# Update a Message Object.

lib/vonage/messaging/channels/messenger.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Messaging::Channels::Messenger < Messaging::Message
77
attr_reader :data
88

99
def initialize(attributes = {})
10+
@to = attributes.fetch(:to, nil)
11+
@from = attributes.fetch(:from, nil)
1012
@type = attributes.fetch(:type, nil)
1113
@message = attributes.fetch(:message, nil)
1214
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/channels/mms.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Messaging::Channels::MMS < Messaging::Message
77
attr_reader :data
88

99
def initialize(attributes = {})
10+
@to = attributes.fetch(:to, nil)
11+
@from = attributes.fetch(:from, nil)
1012
@type = attributes.fetch(:type, nil)
1113
@message = attributes.fetch(:message, nil)
1214
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/channels/rcs.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Messaging::Channels::RCS < Messaging::Message
77
attr_reader :data
88

99
def initialize(attributes = {})
10+
@to = attributes.fetch(:to, nil)
11+
@from = attributes.fetch(:from, nil)
1012
@type = attributes.fetch(:type, nil)
1113
@message = attributes.fetch(:message, nil)
1214
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/channels/sms.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class Messaging::Channels::SMS < Messaging::Message
55
attr_reader :data
66

77
def initialize(attributes = {})
8+
@to = attributes.fetch(:to, nil)
9+
@from = attributes.fetch(:from, nil)
810
@type = attributes.fetch(:type, 'text')
911
@message = attributes.fetch(:message, nil)
1012
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/channels/viber.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Messaging::Channels::Viber < Messaging::Message
77
attr_reader :data
88

99
def initialize(attributes = {})
10+
@to = attributes.fetch(:to, nil)
11+
@from = attributes.fetch(:from, nil)
1012
@type = attributes.fetch(:type, nil)
1113
@message = attributes.fetch(:message, nil)
1214
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/channels/whats_app.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Messaging::Channels::WhatsApp < Messaging::Message
77
attr_reader :data
88

99
def initialize(attributes = {})
10+
@to = attributes.fetch(:to, nil)
11+
@from = attributes.fetch(:from, nil)
1012
@type = attributes.fetch(:type, nil)
1113
@message = attributes.fetch(:message, nil)
1214
@opts = attributes.fetch(:opts, {})

lib/vonage/messaging/message.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def self.method_missing(method)
2525

2626
private
2727

28-
attr_accessor :type, :message, :opts
28+
attr_accessor :to, :from, :type, :message, :opts
2929
attr_writer :data
3030

3131
def after_initialize!
@@ -35,6 +35,8 @@ def after_initialize!
3535
end
3636

3737
def build
38+
data[:to] = to if to
39+
data[:from] = from if from
3840
data[:message_type] = type
3941
data[type.to_sym] = message
4042
data.merge!(opts)

0 commit comments

Comments
 (0)