Skip to content

Commit 30cdc43

Browse files
authored
fix: rework knock client usage (#20)
* fix: rework knock client usage * chore: fix api hostname * chore: fix rubocop
1 parent e1cd14c commit 30cdc43

16 files changed

+131
-68
lines changed

Gemfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
knockapi (0.4.12)
4+
knockapi (0.5.0)
55

66
GEM
77
remote: https://rubygems.org/

README.md

+4-26
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ Or, you may set the key yourself in an initializer:
2626

2727
```ruby
2828
# /config/initializers/knock.rb
29-
Knock.key = 'sk_12345'
29+
Knock.configure do |config|
30+
config.key = '[your api key]'
31+
config.timeout = 120
32+
end
3033
```
3134

3235
## Usage
3336

3437
### Identifying users
3538

3639
```ruby
37-
require "knock"
38-
39-
Knock.key = "sk_12345"
40-
4140
Knock::Users.identify(
4241
id: "jhammond",
4342
data: {
@@ -50,10 +49,6 @@ Knock::Users.identify(
5049
### Sending notifies (triggering workflows)
5150

5251
```ruby
53-
require "knock"
54-
55-
Knock.key = "sk_12345"
56-
5752
# The key of the workflow (from Knock dashboard)
5853
Knock::Workflows.trigger(
5954
key: "dinosaurs-loose",
@@ -74,29 +69,18 @@ Knock::Workflows.trigger(
7469
### Retrieving users
7570

7671
```ruby
77-
require "knock"
78-
79-
Knock.key = "sk_12345"
80-
8172
Knock::Users.get(id: "jhammond")
8273
```
8374

8475
### Deleting users
8576

8677
```ruby
87-
require "knock"
88-
89-
Knock.key = "sk_12345"
90-
9178
Knock::Users.delete(id: "jhammond")
9279
```
9380

9481
### Preferences
9582

9683
```ruby
97-
require "knock"
98-
Knock.key = "sk_12345"
99-
10084
# Set an entire preference set
10185
Knock::Users.set_preferences(
10286
user_id: "jhammond",
@@ -115,9 +99,6 @@ Knock::Users.get_preferences(user_id: "jhammond")
11599
### Getting and setting channel data
116100

117101
```ruby
118-
require "knock"
119-
Knock.key = "sk_12345"
120-
121102
# Set channel data for an APNS
122103
Knock::Users.set_channel_data(
123104
id: "jhammond",
@@ -134,9 +115,6 @@ Knock::Users.get_channel_data(user_id: "jhammond", channel_id: KNOCK_APNS_CHANNE
134115
### Cancelling workflows
135116

136117
```ruby
137-
require "knock"
138-
Knock.key = "sk_12345"
139-
140118
Knock::Workflows.cancel(
141119
key: "dinosaurs-loose",
142120
cancellation_key: trigger_alert.id,

lib/knock.rb

+22-10
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,39 @@
22

33
require 'knock/version'
44
require 'json'
5+
require 'knock/configuration'
56

67
# Setup for Knock client
78
module Knock
8-
API_HOSTNAME = ENV['KNOCK_API_HOSTNAME'] || 'api.knock.app'
9+
def self.default_config
10+
Configuration.new.tap do |config|
11+
config.api_hostname = ENV['KNOCK_API_HOSTNAME'] || 'api.knock.app'
12+
config.key = ENV['KNOCK_API_KEY']
13+
end
14+
end
915

10-
def self.key=(value)
11-
Base.key = value
16+
def self.config
17+
@config ||= default_config
1218
end
1319

14-
def self.key
15-
Base.key
20+
def self.configure
21+
yield(config)
1622
end
1723

18-
def self.key!
19-
key || raise('Knock.key not set')
24+
def self.key=(value)
25+
warn '`Knock.key=` is deprecated. Use `Knock.configure` instead.'
26+
27+
config.key = value
28+
end
29+
30+
def self.key
31+
warn '`Knock.key` is deprecated. Use `Knock.configure` instead.'
32+
config.key
2033
end
2134

2235
autoload :Base, 'knock/base'
2336
autoload :Client, 'knock/client'
37+
autoload :Configuration, 'knock/configuration'
2438

2539
# Resources
2640
autoload :Preferences, 'knock/preferences'
@@ -35,9 +49,7 @@ def self.key!
3549
autoload :APIError, 'knock/errors'
3650
autoload :AuthenticationError, 'knock/errors'
3751
autoload :InvalidRequestError, 'knock/errors'
38-
39-
key = ENV['KNOCK_API_KEY']
40-
Knock.key = key unless key.nil?
52+
autoload :TimeoutError, 'knock/errors'
4153

4254
# Triggers the workflow with the given key
4355
#

lib/knock/base.rb

-12
This file was deleted.

lib/knock/bulk_operations.rb

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module Knock
77
# Provides convienience methods for working with bulk operations
88
module BulkOperations
99
class << self
10-
include Base
1110
include Client
1211

1312
# Retrieves the given bulk operation

lib/knock/client.rb

+19-11
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,27 @@
22

33
module Knock
44
# A Net::HTTP based API client for interacting with the Knock API
5+
# rubocop:disable Metrics/ModuleLength
56
module Client
67
include Kernel
78

89
def client
9-
return @client if defined?(@client)
10-
11-
@client = Net::HTTP.new(Knock::API_HOSTNAME, 443)
12-
@client.use_ssl = true
13-
14-
@client
10+
Net::HTTP.new(Knock.config.api_hostname, 443).tap do |http_client|
11+
http_client.use_ssl = true
12+
http_client.open_timeout = Knock.config.timeout
13+
http_client.read_timeout = Knock.config.timeout
14+
http_client.write_timeout = Knock.config.timeout if RUBY_VERSION >= '2.6.0'
15+
end
1516
end
1617

1718
def execute_request(request:)
18-
response = client.request(request)
19+
begin
20+
response = client.request(request)
21+
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
22+
raise TimeoutError.new(
23+
message: 'API Timeout Error'
24+
)
25+
end
1926

2027
http_status = response.code.to_i
2128
handle_error_response(response: response) if http_status >= 400
@@ -32,15 +39,15 @@ def get_request(path:, auth: false, params: {}, access_token: nil)
3239
'Content-Type' => 'application/json'
3340
)
3441

35-
request['Authorization'] = "Bearer #{access_token || Knock.key!}" if auth
42+
request['Authorization'] = "Bearer #{access_token || Knock.config.key!}" if auth
3643
request['User-Agent'] = user_agent
3744
request
3845
end
3946

4047
def post_request(path:, auth: false, idempotency_key: nil, body: nil)
4148
request = Net::HTTP::Post.new(path, 'Content-Type' => 'application/json')
4249
request.body = body.to_json if body
43-
request['Authorization'] = "Bearer #{Knock.key!}" if auth
50+
request['Authorization'] = "Bearer #{Knock.config.key!}" if auth
4451
request['User-Agent'] = user_agent
4552
request['Idempotency-Key'] = idempotency_key if idempotency_key
4653
request
@@ -56,15 +63,15 @@ def delete_request(path:, auth: false, params: {}, body: nil)
5663
)
5764

5865
request.body = body.to_json if body
59-
request['Authorization'] = "Bearer #{Knock.key!}" if auth
66+
request['Authorization'] = "Bearer #{Knock.config.key!}" if auth
6067
request['User-Agent'] = user_agent
6168
request
6269
end
6370

6471
def put_request(path:, auth: false, idempotency_key: nil, body: nil)
6572
request = Net::HTTP::Put.new(path, 'Content-Type' => 'application/json')
6673
request.body = body.to_json if body
67-
request['Authorization'] = "Bearer #{Knock.key!}" if auth
74+
request['Authorization'] = "Bearer #{Knock.config.key!}" if auth
6875
request['User-Agent'] = user_agent
6976
request['Idempotency-Key'] = idempotency_key if idempotency_key
7077
request
@@ -122,4 +129,5 @@ def extract_error(errors)
122129
end.join('; ')
123130
end
124131
end
132+
# rubocop:enable Metrics/ModuleLength
125133
end

lib/knock/configuration.rb

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
# typed: true
4+
5+
module Knock
6+
# Configuration class sets config initializer
7+
class Configuration
8+
attr_accessor :api_hostname, :timeout, :key
9+
10+
def initialize
11+
@timeout = 60
12+
end
13+
14+
def key!
15+
key or raise '`Knock.config.key` not set'
16+
end
17+
end
18+
end

lib/knock/errors.rb

+3
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,7 @@ class AuthenticationError < KnockError; end
4242
# InvalidRequestError is raised when a request is initiated with invalid
4343
# parameters.
4444
class InvalidRequestError < KnockError; end
45+
46+
# TimeoutError is raised when the HTTP request to the API times out
47+
class TimeoutError < KnockError; end
4548
end

lib/knock/messages.rb

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ module Knock
88
# Methods for interacting with messages in Knock
99
module Messages
1010
class << self
11-
include Base
1211
include Client
1312

1413
# Retrieves a paginated list of messages for the provided environment

lib/knock/objects.rb

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ module Knock
99
# rubocop:disable Metrics/ModuleLength
1010
module Objects
1111
class << self
12-
include Base
1312
include Client
1413

1514
DEFAULT_PREFERENCE_SET_ID = 'default'

lib/knock/preferences.rb

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module Knock
77
# Provides convienience methods for working with preferences (deprecated)
88
module Preferences
99
class << self
10-
include Base
1110
include Client
1211

1312
# Returns all preference sets for the user

lib/knock/tenants.rb

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module Knock
77
# Methods for interacting with tenants in Knock
88
module Tenants
99
class << self
10-
include Base
1110
include Client
1211

1312
# Retrieves all Tenants in environment

lib/knock/users.rb

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ module Knock
99
# rubocop:disable Metrics/ModuleLength
1010
module Users
1111
class << self
12-
include Base
1312
include Client
1413

1514
DEFAULT_PREFERENCE_SET_ID = 'default'

lib/knock/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Knock
4-
VERSION = '0.4.12'
4+
VERSION = '0.5.0'
55
end

lib/knock/workflows.rb

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module Knock
77
# Methods for interacting with workflows in Knock
88
module Workflows
99
class << self
10-
include Base
1110
include Client
1211

1312
# Triggers the workflow with the given key

spec/configuration_spec.rb

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# frozen_string_literal: true
2+
3+
# typed: false
4+
require_relative '../lib/knock'
5+
6+
describe Knock do
7+
describe '.configure' do
8+
context 'with key and no timeout' do
9+
before do
10+
Knock.configure do |config|
11+
config.key = 'example_api_key'
12+
end
13+
end
14+
15+
it 'sets the key and default timeout configuration' do
16+
expect(Knock.config.key).to eq('example_api_key')
17+
expect(Knock.config.timeout).to eq(60)
18+
end
19+
end
20+
21+
context 'with key and timeout' do
22+
before do
23+
Knock.configure do |config|
24+
config.key = 'example_api_key'
25+
config.timeout = 120
26+
end
27+
end
28+
29+
it 'sets the key and timeout configuration' do
30+
expect(Knock.config.key).to eq('example_api_key')
31+
expect(Knock.config.timeout).to eq(120)
32+
end
33+
end
34+
end
35+
end
36+
37+
describe Knock::Configuration do
38+
describe '.key!' do
39+
context 'with key set' do
40+
before do
41+
Knock.config.key = 'example_api_key'
42+
end
43+
44+
it 'returns the key' do
45+
expect(Knock.config.key!).to eq('example_api_key')
46+
end
47+
end
48+
49+
context 'with key not set' do
50+
before do
51+
Knock.config.key = nil
52+
end
53+
54+
it 'throws an error' do
55+
expect do
56+
Knock.config.key!
57+
end.to raise_error(
58+
'`Knock.config.key` not set'
59+
)
60+
end
61+
end
62+
end
63+
end

0 commit comments

Comments
 (0)