Skip to content

Commit

Permalink
Use just one client, the latest one
Browse files Browse the repository at this point in the history
Removing LegacyClient in favor of having one client which handles the
latest response formats. Refactoring implementation and replacing
'httparty' with 'typhoeus'. Updating README and adding tests.
  • Loading branch information
pablonahuelgomez committed Feb 12, 2018
1 parent 82bceed commit 1de36fd
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 118 deletions.
18 changes: 2 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,9 @@ $ gem install exponent-server-sdk

## Usage

### Legacy
### Client

There is a legacy client that uses version 1 of the api. It's simpler but has limitations like only allowing you to publish messages to a single user per call.

```ruby
exponent = Exponent::Push::LegacyClient.new

exponent.publish(
exponentPushToken: token,
message: message,
data: {a: 'b'}, # Any arbitrary data to include with the notification
)
```

### Current

The new client is the preferred way. This hits the latest version of the api.
The push client is the preferred way. This hits the latest version of the api.

```ruby
exponent = Exponent::Push::Client.new
Expand Down
2 changes: 1 addition & 1 deletion exponent-server-sdk.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]

spec.add_dependency "httparty"
spec.add_dependency "typhoeus"

spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
Expand Down
95 changes: 58 additions & 37 deletions lib/exponent-server-sdk.rb
Original file line number Diff line number Diff line change
@@ -1,60 +1,81 @@
require 'exponent-server-sdk/version'

require 'httparty'
require 'typhoeus'
require 'json'

module Exponent
def self.is_exponent_push_token?(token)
token.start_with?('ExponentPushToken')
end

module Push
def self.is_exponent_push_token?(token)
token.start_with?('ExponentPushToken')
end
Error = Class.new(StandardError)

class LegacyClient
class Client

def initialize(new_http_client=nil)
@http_client = new_http_client || HTTParty
def initialize(new_http_client = nil)
@http_client = new_http_client || Typhoeus
end

def publish(options)
data = options.delete(:data)
response = @http_client.post('https://exp.host/--/api/notify/' + ERB::Util.url_encode([options].to_json),
:body => data.to_json,
:headers => {
'Content-Type' => 'application/json'
}
)
def publish(messages)
handle_response(push_notifications(messages))
end

private

case response.code
when 400
raise Exponent::Push::Errors::InvalidPushTokenError
def handle_response(response)
case response.code.to_s
when /(^4|^5)/
error = extract_error(parse_json(response))
raise Error, "#{error.fetch('code')} -> #{error.fetch('message')}"
else
handle_success(parse_json(response).fetch('data').first)
end
end
end

class Client
def parse_json(response)
JSON.parse(response.body)
end

def initialize(new_http_client=nil)
@http_client = new_http_client || HTTParty
def extract_error(body)
if body.respond_to?(:fetch)
body.fetch('errors').first { unknown_error }
else
unknown_error
end
end

def publish(messages)
response = @http_client.post('https://exp.host/--/api/v2/push/send',
attr_reader :http_client

def push_notifications(messages)
http_client.post(
push_url,
body: messages.to_json,
headers: {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Accept-Encoding' => 'gzip, deflate'
}
headers: headers
)
end

case response.code
when 400
raise Exponent::Push::Errors::InvalidPushTokenError
end
def push_url
'https://exp.host/--/api/v2/push/send'
end

def headers
{
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Accept-Encoding' => 'gzip, deflate'
}
end

def handle_success(data)
return data if data.fetch('status') == 'ok'
raise Exponent::Push::Error, "#{data['details']['error']} -> #{data['message']}"
end
end

module Errors
class InvalidPushTokenError < StandardError
def unknown_error
{
'code' => 'Unknown code',
'message' => 'Unknown message'
}
end
end
end
Expand Down
130 changes: 66 additions & 64 deletions test/exponent-server-sdk-test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,76 @@
require 'exponent-server-sdk'

class ExponentServerSdkTest < Minitest::Test
def test_publish
mock = MiniTest::Mock.new
response_mock = MiniTest::Mock.new
exponent = Exponent::Push::Client.new mock
def setup
@mock = MiniTest::Mock.new
@response_mock = MiniTest::Mock.new
@exponent = Exponent::Push::Client.new(@mock)
end

response_mock.expect(:code, 200)
def test_publish_with_success
@response_mock.expect(:code, 200)
@response_mock.expect(:body, success_body.to_json)

messages = [{
to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
sound: "default",
body: "Hello world!"
}, {
to: "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]",
badge: 1,
body: "You've got mail"
}]
@mock.expect(:post, @response_mock, client_args)

args = [
'https://exp.host/--/api/v2/push/send',
{
body: messages.to_json,
headers: {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Accept-Encoding' => 'gzip, deflate'
}
}
]
mock.expect(:post, response_mock, args)
@exponent.publish(messages)

messages = [{
to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
sound: "default",
body: "Hello world!"
}, {
to: "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]",
badge: 1,
body: "You've got mail"
}]
@mock.verify
end

def test_publish_with_error
@response_mock.expect(:code, 400)
@response_mock.expect(:body, error_body.to_json)

exponent.publish(messages)
@mock.expect(:post, @response_mock, client_args)

mock.verify
assert_raises Exponent::Push::Error do
@exponent.publish(messages)
end

@mock.verify
end

def test_publish_with_error
mock = MiniTest::Mock.new
response_mock = MiniTest::Mock.new
exponent = Exponent::Push::Client.new mock
def test_publish_with_success_and_errors
@response_mock.expect(:code, 200)
@response_mock.expect(:body, success_with_error_body.to_json)

response_mock.expect(:code, 400)
@mock.expect(:post, @response_mock, client_args)

messages = [{
to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
sound: "default",
body: "Hello world!"
}, {
to: "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]",
badge: 1,
body: "You've got mail"
}]
assert_raises Exponent::Push::Error do
@exponent.publish(messages)
end

@mock.verify
end

private

args = [
def success_body
{ 'data' => [{ 'status' => 'ok' }] }
end

def error_body
{
'errors' => [{
'code' => 'INTERNAL_SERVER_ERROR',
'message' => 'An unknown error occurred.'
}]
}
end

def success_with_error_body
{
'data' => [{
'status' => 'error',
'message' => '"ExponentPushToken[42]" is not a registered push notification recipient',
'details' => { 'error' => 'DeviceNotRegistered' }
}]
}
end

def client_args
[
'https://exp.host/--/api/v2/push/send',
{
body: messages.to_json,
Expand All @@ -75,22 +82,17 @@ def test_publish_with_error
}
}
]
mock.expect(:post, response_mock, args)
end

messages = [{
to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
sound: "default",
body: "Hello world!"
def messages
[{
to: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]',
sound: 'default',
body: 'Hello world!'
}, {
to: "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]",
to: 'ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]',
badge: 1,
body: "You've got mail"
}]

assert_raises Exponent::Push::Errors::InvalidPushTokenError do
exponent.publish(messages)
end

mock.verify
end
end

0 comments on commit 1de36fd

Please sign in to comment.