Skip to content

Commit

Permalink
support for sending transactional push messages (#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
karngyan authored May 8, 2023
1 parent 5f310b8 commit f9984a7
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.markdown
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Customerio 5.1.0 - May 5, 2023
### Added
- Added `send_push` to `APIClient` and `SendPushRequest` to support sending transactional push notifications.

## Customerio 4.3.1 - January 5, 2023
### Added
- Added the `disable_css_preprocessing` and `language` optional fields to send request
Expand Down
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ $customerio.unsuppress(5)

### Send Transactional Messages

To use the Customer.io [Transactional API](https://customer.io/docs/transactional-api), create an instance of the API client using an [app key](https://customer.io/docs/managing-credentials#app-api-keys).
To use the Customer.io [Transactional API](https://customer.io/docs/transactional-api), create an instance of the API client using an [app key](https://customer.io/docs/managing-credentials#app-api-keys) and create a request object of your message type.

#### Email

Create a new `SendEmailRequest` object containing:

Expand Down Expand Up @@ -262,6 +264,44 @@ rescue Customerio::InvalidResponse => e
end
```

#### Push

Create a new `SendPushRequest` object containing:

* `transactional_message_id`: the ID or trigger name of the transactional message you want to send.
* an `identifiers` object containing the `id` or `email` of your recipient. If the profile does not exist, Customer.io creates it.

Use `send_push` referencing your request to send a transactional message. [Learn more about transactional messages and `SendPushRequest` properties](https://customer.io/docs/transactional-api).


```ruby
require "customerio"

client = Customerio::APIClient.new("your API key", region: Customerio::Regions::US)

request = Customerio::SendPushRequest.new(
transactional_message_id: "3",
message_data: {
name: "Person",
items: {
name: "shoes",
price: "59.99",
},
products: [],
},
identifiers: {
id: "2",
},
)

begin
response = client.send_push(request)
puts response
rescue Customerio::InvalidResponse => e
puts e.code, e.message
end
```

## Contributing

1. Fork it
Expand Down
1 change: 1 addition & 0 deletions lib/customerio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Customerio
require "customerio/base_client"
require "customerio/client"
require "customerio/requests/send_email_request"
require "customerio/requests/send_push_request"
require "customerio/api"
require "customerio/param_encoder"
end
19 changes: 19 additions & 0 deletions lib/customerio/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,29 @@ def send_email(req)
end
end

def send_push(req)
raise "request must be an instance of Customerio::SendPushRequest" unless req.is_a?(Customerio::SendPushRequest)
response = @client.request(:post, send_push_path, req.message)

case response
when Net::HTTPSuccess then
JSON.parse(response.body)
when Net::HTTPBadRequest then
json = JSON.parse(response.body)
raise Customerio::InvalidResponse.new(response.code, json['meta']['error'], response)
else
raise InvalidResponse.new(response.code, response.body)
end
end

private

def send_email_path
"/v1/send/email"
end

def send_push_path
"/v1/send/push"
end
end
end
36 changes: 36 additions & 0 deletions lib/customerio/requests/send_push_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Customerio
class SendPushRequest
attr_reader :message

def initialize(opts)
@message = opts.delete_if { |field| invalid_field?(field) }
@message[:custom_device] = opts[:device] if opts[:device]
end

private

REQUIRED_FIELDS = %i(transactional_message_id identifiers)

OPTIONAL_FIELDS = %i(
to
title
message
disable_message_retention
send_to_unsubscribed
queue_draft
message_data
send_at
language
image_url
link
sound
custom_data
device
custom_device
)

def invalid_field?(field)
!REQUIRED_FIELDS.include?(field) && !OPTIONAL_FIELDS.include?(field)
end
end
end
2 changes: 1 addition & 1 deletion lib/customerio/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Customerio
VERSION = "5.0.0"
VERSION = "5.1.0"
end
85 changes: 84 additions & 1 deletion spec/api_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
describe Customerio::APIClient do
let(:app_key) { "appkey" }

let(:client) { Customerio::APIClient.new(app_key) }
let(:client) { Customerio::APIClient.new(app_key) }
let(:response) { double("Response", code: 200) }

def api_uri(path)
Expand Down Expand Up @@ -169,4 +169,87 @@ def json(data)
req.message[:attachments].should eq({ "test" => Base64.strict_encode64("test-content") })
end
end

describe "#send_push" do
it "sends a POST request to the /api/send/push path" do
req = Customerio::SendPushRequest.new(
identifiers: {
id: 'c1',
},
transactional_message_id: 1,
)

stub_request(:post, api_uri('/v1/send/push'))
.with(headers: request_headers, body: req.message)
.to_return(status: 200, body: { delivery_id: 1 }.to_json, headers: {})

client.send_push(req).should eq({ "delivery_id" => 1 })
end

it "handles validation failures (400)" do
req = Customerio::SendPushRequest.new(
identifiers: {
id: 'c1',
},
transactional_message_id: 1,
)

err_json = { meta: { error: "example error" } }.to_json

stub_request(:post, api_uri('/v1/send/push'))
.with(headers: request_headers, body: req.message)
.to_return(status: 400, body: err_json, headers: {})

lambda { client.send_push(req) }.should(
raise_error(Customerio::InvalidResponse) { |error|
error.message.should eq "example error"
error.code.should eq "400"
}
)
end

it "handles other failures (5xx)" do
req = Customerio::SendPushRequest.new(
identifiers: {
id: 'c1',
},
transactional_message_id: 1,
)

stub_request(:post, api_uri('/v1/send/push'))
.with(headers: request_headers, body: req.message)
.to_return(status: 500, body: "Server unavailable", headers: {})

lambda { client.send_push(req) }.should(
raise_error(Customerio::InvalidResponse) { |error|
error.message.should eq "Server unavailable"
error.code.should eq "500"
}
)
end

it "sets custom_device correctly if device present in req" do
req = Customerio::SendPushRequest.new(
identifiers: {
id: 'c1',
},
transactional_message_id: 1,
device: {
platform: 'ios',
token: 'sample-token',
}
)

req.message[:custom_device].should eq({
platform: 'ios',
token: 'sample-token',
})

stub_request(:post, api_uri('/v1/send/push'))
.with(headers: request_headers, body: req.message)
.to_return(status: 200, body: { delivery_id: 2 }.to_json, headers: {})

client.send_push(req).should eq({ "delivery_id" => 2 })
end
end
end

0 comments on commit f9984a7

Please sign in to comment.