my_target_api 1.2.4 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 332efd986b48d1eb9282a1d9f279af9a73c0d68c
4
- data.tar.gz: d5c0aaed3310f3916c89efe27429eeeceee0a613
3
+ metadata.gz: 4254318b97e9d1f594438694a31a6511ea9461fc
4
+ data.tar.gz: 69e005cf224551553abdc2c047d84b278a3f3e70
5
5
  SHA512:
6
- metadata.gz: e76f8ff06d6cf4babe4d373a4b16f8205741f2d5f271f8cd435018775036b37444384519d36dcdcaac36abcfcb5f8f41d6e0969362e7dc769a6d5b4b49906e23
7
- data.tar.gz: 711ddc0150a890da7c0e31ca94dfa4227e3139cc009e6eec8ca5cce194e0d15ec61d0207035b497355b0a8d4aaf3bf67d6c6e8f292ef17061d260dceb9c60ec4
6
+ metadata.gz: '08db4857b6fb49cacdc2050356b43aa94b3998fb2a8f0d31fc133e12554b07d190e0a370363b9b8bc5dfa88a53717c91b449b0ba5de5d1254dab65bfd3e93c38'
7
+ data.tar.gz: '08966200b98a7df2bfc4fee600650072ee52343e5ff3f83b987a450cd915901ee88b2273aea35e67b6a40f66e50020a75ee68ac35e66b713f14207d5aa12fe3b'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- my_target_api (1.2.4)
4
+ my_target_api (2.0.1)
5
5
  json (~> 2.0, >= 2.0.0)
6
6
  rest-client (~> 2.0, >= 2.0.0)
7
7
 
@@ -10,7 +10,7 @@ GEM
10
10
  specs:
11
11
  addressable (2.6.0)
12
12
  public_suffix (>= 2.0.2, < 4.0)
13
- ast (2.4.0)
13
+ ast (2.4.1)
14
14
  crack (0.4.3)
15
15
  safe_yaml (~> 1.0.0)
16
16
  diff-lcs (1.3)
@@ -24,17 +24,18 @@ GEM
24
24
  mime-types-data (~> 3.2015)
25
25
  mime-types-data (3.2018.0812)
26
26
  netrc (0.11.0)
27
- parallel (1.13.0)
28
- parser (2.6.0.0)
29
- ast (~> 2.4.0)
30
- powerpack (0.1.2)
27
+ parallel (1.19.2)
28
+ parser (2.7.1.4)
29
+ ast (~> 2.4.1)
31
30
  public_suffix (3.0.3)
32
31
  rainbow (3.0.0)
33
32
  rake (12.3.2)
33
+ regexp_parser (1.7.1)
34
34
  rest-client (2.0.2)
35
35
  http-cookie (>= 1.0.2, < 2.0)
36
36
  mime-types (>= 1.16, < 4.0)
37
37
  netrc (~> 0.8)
38
+ rexml (3.2.4)
38
39
  rspec (3.7.0)
39
40
  rspec-core (~> 3.7.0)
40
41
  rspec-expectations (~> 3.7.0)
@@ -48,19 +49,23 @@ GEM
48
49
  diff-lcs (>= 1.2.0, < 2.0)
49
50
  rspec-support (~> 3.7.0)
50
51
  rspec-support (3.7.1)
51
- rubocop (0.54.0)
52
+ rubocop (0.89.1)
52
53
  parallel (~> 1.10)
53
- parser (>= 2.5)
54
- powerpack (~> 0.1)
54
+ parser (>= 2.7.1.1)
55
55
  rainbow (>= 2.2.2, < 4.0)
56
+ regexp_parser (>= 1.7)
57
+ rexml
58
+ rubocop-ast (>= 0.3.0, < 1.0)
56
59
  ruby-progressbar (~> 1.7)
57
- unicode-display_width (~> 1.0, >= 1.0.1)
58
- ruby-progressbar (1.10.0)
60
+ unicode-display_width (>= 1.4.0, < 2.0)
61
+ rubocop-ast (0.3.0)
62
+ parser (>= 2.7.1.4)
63
+ ruby-progressbar (1.10.1)
59
64
  safe_yaml (1.0.4)
60
65
  unf (0.1.4)
61
66
  unf_ext
62
67
  unf_ext (0.0.7.5)
63
- unicode-display_width (1.4.1)
68
+ unicode-display_width (1.7.0)
64
69
  webmock (2.3.2)
65
70
  addressable (>= 2.3.6)
66
71
  crack (>= 0.3.2)
@@ -70,12 +75,12 @@ PLATFORMS
70
75
  ruby
71
76
 
72
77
  DEPENDENCIES
73
- bundler (~> 1.6)
78
+ bundler (~> 2.1.4)
74
79
  my_target_api!
75
80
  rake (~> 12.3.0, >= 12.3.0)
76
81
  rspec (~> 3.7.0, >= 3.7.0)
77
- rubocop (~> 0.54.0)
82
+ rubocop (~> 0.89.1)
78
83
  webmock (~> 2.3.2, >= 2.3.2)
79
84
 
80
85
  BUNDLED WITH
81
- 1.16.1
86
+ 2.1.4
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```
10
- gem 'my_target_api', '~> 1.2.4'
10
+ gem 'my_target_api', '~> 2.0.1'
11
11
  ```
12
12
 
13
13
  Or install from command line:
@@ -43,6 +43,7 @@ Name | Default value | Description
43
43
  ---|---|---
44
44
  `:v` | 1 | API version
45
45
  `:logger` | | An object to log requests and exceptions. The object must respond to `<<` method
46
+ `:headers` | | Headers hash to pass with request
46
47
 
47
48
  ### Create, Read, Update, Delete
48
49
 
@@ -60,7 +61,7 @@ remarketing_counters_resource.delete(id: 343434) # => [{ 'success' => true }]
60
61
 
61
62
  #### Options
62
63
 
63
- Name | Default value | Description
64
+ Name | Default value | Description
64
65
  ---|---|---
65
66
  `:id` | | Resource ID. Optional for Read, required for Update and Delete
66
67
  `:id_param_key` | `:id` | Option key for resource ID
@@ -96,19 +97,18 @@ def read_active_campaigns
96
97
 
97
98
  campaigns_resource.read(status: 'active')
98
99
 
99
- rescue MyTargetApi::RequestError, MyTargetApi::ConnectionError => e
100
+ rescue MyTargetApi::RequestError => e
100
101
 
101
- puts e.message, e.backtrace
102
+ puts e.message, e.params, e.response, e.backtrace
102
103
  # You can access the original exception
103
- puts e.original_exception.message, e.original_exception.backtrace
104
+ puts e.original_exception&.message, e.original_exception&.backtrace
104
105
 
105
106
  end
106
107
  ```
107
108
 
108
- Name | Description
109
+ Name | Description
109
110
  ---|---
110
111
  `MyTargetApi::RequestError` | Request didn't succeed
111
- `MyTargetApi::ConnectionError` | Connection didn't succeed
112
112
 
113
113
  ## Testing
114
114
 
@@ -7,9 +7,9 @@ class MyTargetApi
7
7
 
8
8
  autoload :Resource, 'my_target_api/resource'
9
9
  autoload :Request, 'my_target_api/request'
10
-
11
- autoload :ConnectionError, 'my_target_api/connection_error'
12
10
  autoload :RequestError, 'my_target_api/request_error'
11
+ autoload :NetClient, 'my_target_api/net_client'
12
+ autoload :LogRequestParametersDecorator, 'my_target_api/log_request_parameters_decorator'
13
13
 
14
14
  def initialize(access_token, options = {})
15
15
  @access_token = access_token
@@ -44,7 +44,14 @@ class MyTargetApi
44
44
  attr_reader :access_token, :options
45
45
 
46
46
  def request_object
47
- Request.new(logger: options[:logger], access_token: access_token)
47
+ @_request_object ||= begin
48
+ options = {
49
+ logger: self.options[:logger],
50
+ access_token: access_token,
51
+ headers: self.options[:headers]
52
+ }
53
+ LogRequestParametersDecorator.new(Request.new(options), options)
54
+ end
48
55
  end
49
56
 
50
57
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative './response_formatter'
5
+ require_relative './net_client'
6
+
7
+ class MyTargetApi
8
+ # Requests
9
+ class LogRequestParametersDecorator
10
+
11
+ def initialize(origin, options = {})
12
+ @origin = origin
13
+ @options = options
14
+ end
15
+
16
+ def get(url, params = {})
17
+ log_hash(method: 'Request#get', url: url, params: params)
18
+
19
+ origin.get(url, params)
20
+ end
21
+
22
+ def post(url, params = {})
23
+ log_hash(method: 'Request#post', url: url, params: params)
24
+
25
+ origin.post(url, params)
26
+ end
27
+
28
+ def delete(url, params = {})
29
+ log_hash(method: 'Request#delete', url: url, params: params)
30
+
31
+ origin.delete(url, params)
32
+ end
33
+
34
+ def upload(url, content, params = {})
35
+ log_hash(method: 'Request#upload', url: url, params: params, content: 'no logging')
36
+
37
+ origin.upload(url, content, params)
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :origin, :options
43
+
44
+ def log_hash(hash)
45
+ log(hash.map do |key, value|
46
+ "#{key}: #{value.is_a?(String) ? value : value.inspect}"
47
+ end.join("\n"))
48
+ end
49
+
50
+ def log(message)
51
+ options[:logger] << message if options[:logger]
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'rest-client'
5
+
6
+ class MyTargetApi
7
+ # Requests
8
+ class NetClient
9
+
10
+ # NetClient response
11
+ class Response
12
+
13
+ def initialize(body, code, headers)
14
+ @body = body
15
+ @code = code
16
+ @headers = headers
17
+ end
18
+
19
+ attr_reader :body, :code, :headers
20
+
21
+ end
22
+
23
+ # NetClient exception
24
+ class Exception < StandardError
25
+
26
+ def initialize(exception, message)
27
+ @original_exception = exception
28
+
29
+ super(message)
30
+ end
31
+
32
+ attr_reader :original_exception
33
+
34
+ end
35
+
36
+ class << self
37
+
38
+ def get(*args)
39
+ RestClient.get(*args) { |response, &block| process_response(response, &block) }
40
+ rescue StandardError => e
41
+ raise(Exception.new(e, e.message).tap { e.set_backtrace(caller) })
42
+ end
43
+
44
+ def post(*args)
45
+ RestClient.post(*args) { |response, &block| process_response(response, &block) }
46
+ rescue StandardError => e
47
+ raise(Exception.new(e, e.message).tap { e.set_backtrace(caller) })
48
+ end
49
+
50
+ def delete(*args)
51
+ RestClient.delete(*args) { |response, &block| process_response(response, &block) }
52
+ rescue StandardError => e
53
+ raise(Exception.new(e, e.message).tap { e.set_backtrace(caller) })
54
+ end
55
+
56
+ private
57
+
58
+ def process_response(response, &block)
59
+ result =
60
+ case response.code
61
+ when 200..207, 400..599
62
+ response
63
+ else
64
+ response.return!(&block)
65
+ end
66
+ Response.new(result.body, result.code, format_headers(result.headers))
67
+ rescue StandardError => e
68
+ raise(Exception.new(e, e.message).tap { e.set_backtrace(caller) })
69
+ end
70
+
71
+ def format_headers(headers)
72
+ headers.map do |key, value|
73
+ [key.to_s.split('_').map(&:capitalize).join('-'), value]
74
+ end.to_h
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'rest-client'
4
+ require_relative './response_formatter'
5
+ require_relative './net_client'
5
6
 
6
7
  class MyTargetApi
7
8
  # Requests
@@ -12,41 +13,35 @@ class MyTargetApi
12
13
  end
13
14
 
14
15
  def get(url, params = {})
15
- log_hash(method: 'Request#get', url: url, params: params)
16
-
17
- response = with_exception_handling do
18
- RestClient.get(url, headers.merge(query(params)))
16
+ response = with_exception_handling(params) do
17
+ NetClient.get(url, headers.merge(query(params)))
19
18
  end
20
19
 
21
20
  process_response(response)
22
21
  end
23
22
 
24
23
  def post(url, params = {})
25
- log_hash(method: 'Request#post', url: url, params: params)
26
-
27
- response = with_exception_handling do
28
- RestClient.post(url, body_parameters(params), headers)
24
+ response = with_exception_handling(params) do
25
+ NetClient.post(url, body_parameters(params), headers)
29
26
  end
30
27
 
31
28
  process_response(response)
32
29
  end
33
30
 
34
31
  def delete(url, params = {})
35
- log_hash(method: 'Request#delete', url: url, params: params)
36
-
37
- response = with_exception_handling do
38
- RestClient.delete(url, headers.merge(query(params)))
32
+ response = with_exception_handling(params) do
33
+ NetClient.delete(url, headers.merge(query(params)))
39
34
  end
40
35
 
41
36
  process_response(response)
42
37
  end
43
38
 
44
39
  def upload(url, content, params = {})
45
- log_hash(method: 'Request#upload', url: url, params: params, content: 'no logging')
46
-
47
- response = with_exception_handling do
48
- RestClient.post(
49
- url, content, headers.merge(query(params)).merge(content_type: 'application/octet-stream')
40
+ response = with_exception_handling(params) do
41
+ NetClient.post(
42
+ url,
43
+ content,
44
+ headers.merge(query(params)).merge('Content-Type' => 'application/octet-stream')
50
45
  )
51
46
  end
52
47
 
@@ -68,9 +63,9 @@ class MyTargetApi
68
63
  end
69
64
 
70
65
  def individual_body_parameters(params)
71
- params.map do |name, value|
72
- [name, value.is_a?(Array) || value.is_a?(Hash) ? value.to_json : value]
73
- end.to_h
66
+ params.transform_values do |value|
67
+ value.is_a?(Array) || value.is_a?(Hash) ? value.to_json : value
68
+ end
74
69
  end
75
70
 
76
71
  def query(params)
@@ -78,7 +73,11 @@ class MyTargetApi
78
73
  end
79
74
 
80
75
  def headers
81
- { Authorization: "Bearer #{access_token}" }
76
+ if access_token
77
+ optional_headers.merge('Authorization' => "Bearer #{access_token}")
78
+ else
79
+ optional_headers
80
+ end
82
81
  end
83
82
 
84
83
  def process_response(response)
@@ -87,38 +86,33 @@ class MyTargetApi
87
86
  response.body
88
87
  end
89
88
 
90
- def with_exception_handling
89
+ def with_exception_handling(params)
91
90
  response = yield
92
- log(response)
91
+ log_response(response)
92
+ raise_with_params(params: params, response: response) if response.code >= 400
93
93
  response
94
- rescue RestClient::ExceptionWithResponse => e
95
- log_rest_client_exception(e)
96
- raise MyTargetApi::RequestError, e
97
- rescue RestClient::Exception => e
98
- log("#{e.class.name} #{e.message}")
99
- raise MyTargetApi::RequestError, e
100
- rescue SocketError => e
101
- raise MyTargetApi::ConnectionError, e
94
+ rescue NetClient::Exception => e
95
+ original_exception = e.original_exception
96
+ log("#{original_exception.class.name} #{original_exception.message}")
97
+ raise_with_params(params: params, original_exception: original_exception)
102
98
  end
103
99
 
104
- def log_rest_client_exception(exception)
105
- log_message =
106
- <<-LOG
107
- RestClient exception
108
- Class: #{exception.class}
109
- Message: #{exception.message}
110
- HTTP Code: #{exception.http_code}
111
- HTTP Body: #{exception.http_body}
112
- HTTP headers: #{exception.http_headers}
113
- LOG
100
+ def log_response(response)
101
+ log(ResponseFormatter.new(response).format)
102
+ end
114
103
 
115
- log(log_message)
104
+ def headers_to_string(headers)
105
+ headers.map do |name, value|
106
+ "#{name}: #{value}"
107
+ end.join("\n")
116
108
  end
117
109
 
118
- def log_hash(hash)
119
- log(hash.map do |key, value|
120
- "#{key}: #{value.is_a?(String) ? value : value.inspect}"
121
- end.join("\n"))
110
+ def raise_with_params(params:, response: nil, original_exception: nil)
111
+ result = MyTargetApi::RequestError.new(params: params,
112
+ response: response,
113
+ original_exception: original_exception)
114
+ result.set_backtrace(caller)
115
+ raise result
122
116
  end
123
117
 
124
118
  def log(message)
@@ -129,5 +123,9 @@ class MyTargetApi
129
123
  options[:access_token]
130
124
  end
131
125
 
126
+ def optional_headers
127
+ options[:headers] || {}
128
+ end
129
+
132
130
  end
133
131
  end
@@ -4,24 +4,18 @@ class MyTargetApi
4
4
  # Error for request
5
5
  class RequestError < StandardError
6
6
 
7
- attr_reader :original_exception
7
+ attr_reader :params, :original_exception, :response
8
8
 
9
- def initialize(exception)
10
- @original_exception = exception
11
- super build_message exception
12
- end
9
+ def initialize(params:, original_exception: nil, response: nil)
10
+ @params = params
11
+ @response = response
12
+ @original_exception = original_exception
13
13
 
14
- private
14
+ message =
15
+ "#{(response ? "#{response.code}: #{response.body}. " : '')}"\
16
+ 'Inspect #params, #response and #original_exception for more details'
15
17
 
16
- def build_message(exception)
17
- body = JSON.parse exception.response
18
- if body['error']
19
- "#{body['error']} : #{body['error_description']}"
20
- else
21
- body.map { |field, error| "#{field}: #{error}" }.join(', ')
22
- end
23
- rescue StandardError
24
- exception.response
18
+ super(message)
25
19
  end
26
20
 
27
21
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ class MyTargetApi
6
+ # Format response
7
+ class ResponseFormatter
8
+
9
+ def initialize(response)
10
+ @response = response
11
+ end
12
+
13
+ def format
14
+ headers = response.headers.empty? ? ' No headers' : "\n#{headers_in_lines}"
15
+ body = response.body.to_s == '' ? ' No body' : "\n#{response.body}"
16
+ <<~RESPONSE
17
+ HTTP Code: #{response.code}
18
+ HTTP Body:#{body}
19
+ HTTP Headers:#{headers}
20
+ RESPONSE
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :response
26
+
27
+ def headers_in_lines
28
+ headers.map do |name, value|
29
+ "#{name}: #{value}"
30
+ end.join("\n")
31
+ end
32
+
33
+ def headers
34
+ @_headers ||= response.headers
35
+ end
36
+
37
+ end
38
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  class MyTargetApi
4
4
 
5
- VERSION = '1.2.4'
5
+ VERSION = '2.0.2'
6
6
 
7
7
  end
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
17
17
  DESC
18
18
  spec.homepage = 'https://github.com/resivalex/my_target_api'
19
19
  spec.license = 'MIT'
20
+ spec.required_ruby_version = '>= 2.4.0'
20
21
 
21
22
  spec.files = Dir['**/*']
22
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -26,9 +27,9 @@ Gem::Specification.new do |spec|
26
27
  spec.add_runtime_dependency 'json', '~> 2.0', '>= 2.0.0'
27
28
  spec.add_runtime_dependency 'rest-client', '~> 2.0', '>= 2.0.0'
28
29
 
29
- spec.add_development_dependency 'bundler', '~> 1.6'
30
+ spec.add_development_dependency 'bundler', '~> 2.1.4'
30
31
  spec.add_development_dependency 'rake', '~> 12.3.0', '>= 12.3.0'
31
32
  spec.add_development_dependency 'rspec', '~> 3.7.0', '>= 3.7.0'
32
- spec.add_development_dependency 'rubocop', '~> 0.54.0'
33
+ spec.add_development_dependency 'rubocop', '~> 0.89.1'
33
34
  spec.add_development_dependency 'webmock', '~> 2.3.2', '>= 2.3.2'
34
35
  end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'my_target_api'
4
+
5
+ describe MyTargetApi::NetClient do
6
+ describe '#post' do
7
+ it 'OK' do
8
+ stub_request(:post, 'https://api.com')
9
+ .with(body: 'param1=1&param2[two]=2')
10
+ .to_return(body: 'body')
11
+
12
+ expect(
13
+ MyTargetApi::NetClient.post('https://api.com', param1: 1, param2: { two: 2 }).body
14
+ ).to eq('body')
15
+ end
16
+
17
+ it 'Content-Type' do
18
+ stub_request(:post, 'https://api.com')
19
+ .with(body: 'payload',
20
+ headers: { 'Content-Type' => 'application/octet-stream' })
21
+ .to_return(body: '{}')
22
+
23
+ expect(
24
+ MyTargetApi::NetClient.post('https://api.com',
25
+ 'payload',
26
+ 'Content-Type' => 'application/octet-stream').body
27
+ ).to eq('{}')
28
+ end
29
+ end
30
+
31
+ describe '#get' do
32
+ it 'OK' do
33
+ stub_request(:get, 'https://api.com?p=3').to_return(body: 'body')
34
+
35
+ expect(MyTargetApi::NetClient.get('https://api.com', params: { p: 3 }).body).to eq('body')
36
+ end
37
+
38
+ it 'Content-Type' do
39
+ stub_request(:get, 'https://api.com/?param1=1&param2%5Btwo%5D=2')
40
+ .with(headers: { 'Content-Type' => 'application/octet-stream' })
41
+ .to_return(body: '{}')
42
+
43
+ expect(MyTargetApi::NetClient.get(
44
+ 'https://api.com',
45
+ params: { param1: 1, param2: { two: 2 } },
46
+ 'Content-Type' => 'application/octet-stream'
47
+ ).body).to eq('{}')
48
+ end
49
+
50
+ it ':content_type' do
51
+ stub_request(:get, 'https://api.com')
52
+ .with(headers: { 'Content-Type' => 'application/octet-stream' })
53
+ .to_return(body: 'abc')
54
+
55
+ expect(
56
+ MyTargetApi::NetClient.get('https://api.com', content_type: 'application/octet-stream').body
57
+ ).to eq('abc')
58
+ end
59
+
60
+ it 'Headers' do
61
+ stub_request(:get, 'https://api.com?p=3')
62
+ .to_return(body: 'body', headers: { 'app-version' => '344354325' })
63
+
64
+ result = MyTargetApi::NetClient.get('https://api.com', params: { p: 3 })
65
+
66
+ expect(result.body).to eq('body')
67
+ expect(result.code).to eq(200)
68
+ expect(result.headers).to eq('App-Version' => '344354325')
69
+ end
70
+
71
+ it '404' do
72
+ stub_request(:get, 'https://api.com').to_return(body: 'not found', status: 404)
73
+
74
+ result = MyTargetApi::NetClient.get('https://api.com', {})
75
+
76
+ expect(result.body).to eq('not found')
77
+ expect(result.code).to eq(404)
78
+ end
79
+
80
+ it '301' do
81
+ stub_request(:get, 'https://api.com')
82
+ .to_return(body: 'not found', status: 301, headers: { 'Location' => 'https://api2.com' })
83
+ stub_request(:get, 'https://api2.com/').to_return(body: 'OK', status: 200)
84
+
85
+ result = MyTargetApi::NetClient.get('https://api.com', {})
86
+
87
+ expect(result.body).to eq('OK')
88
+ expect(result.code).to eq(200)
89
+ end
90
+ end
91
+
92
+ describe '#delete' do
93
+ it 'OK' do
94
+ stub_request(:delete, 'https://api.com').to_return(body: 'body')
95
+
96
+ expect(MyTargetApi::NetClient.delete('https://api.com', {}).body).to eq('body')
97
+ end
98
+
99
+ it 'Content-Type' do
100
+ stub_request(:delete, 'https://api.com/?param1=1&param2%5Btwo%5D=2')
101
+ .with(headers: { 'Content-Type' => 'application/octet-stream' })
102
+ .to_return(body: '{}')
103
+
104
+ expect(MyTargetApi::NetClient.delete(
105
+ 'https://api.com',
106
+ params: { param1: 1, param2: { two: 2 } },
107
+ 'Content-Type' => 'application/octet-stream'
108
+ ).body).to eq('{}')
109
+ end
110
+
111
+ it '404' do
112
+ stub_request(:delete, 'https://api.com').to_return(body: 'not found', status: 404)
113
+
114
+ result = MyTargetApi::NetClient.delete('https://api.com', {})
115
+
116
+ expect(result.body).to eq('not found')
117
+ expect(result.code).to eq(404)
118
+ end
119
+ end
120
+ end
@@ -3,8 +3,6 @@
3
3
  require 'my_target_api'
4
4
 
5
5
  describe MyTargetApi::Request do
6
- let(:access_token) { 'myTarget token' }
7
-
8
6
  let(:request) { MyTargetApi::Request.new }
9
7
 
10
8
  describe 'myTarget request types' do
@@ -16,41 +14,69 @@ describe MyTargetApi::Request do
16
14
 
17
15
  describe 'request something' do
18
16
  it 'return parsed json' do
19
- stub_request(:post, 'https://target.my.com/api/v1/campaigns.json')
20
- .to_return(body: '{"name": "Campaign 1"}')
17
+ allow(MyTargetApi::NetClient).to(
18
+ receive(:post).and_return(double(code: 200, body: '{"name": "Campaign 1"}', headers: {}))
19
+ )
20
+
21
+ result = subject.post('https://target.my.com/api/v1/campaigns.json')
21
22
 
22
- expect(subject.post('https://target.my.com/api/v1/campaigns.json'))
23
- .to eq('name' => 'Campaign 1')
23
+ expect(MyTargetApi::NetClient).to(
24
+ have_received(:post).with('https://target.my.com/api/v1/campaigns.json', '{}', {})
25
+ )
26
+
27
+ expect(result).to eq('name' => 'Campaign 1')
24
28
  end
25
29
 
26
30
  it 'pass parameters by url in get' do
27
- stub_request(:get, 'https://target.my.com/api/v1/vk_groups.json?q=unfound')
28
- .to_return(body: '[]')
31
+ allow(MyTargetApi::NetClient)
32
+ .to receive(:get).and_return(double(code: 200, body: '[]', headers: {}))
33
+
34
+ result = subject.get('https://target.my.com/api/v1/vk_groups.json', q: 'unfound')
29
35
 
30
- expect(subject.get('https://target.my.com/api/v1/vk_groups.json', q: 'unfound'))
31
- .to eq([])
36
+ expect(MyTargetApi::NetClient).to(
37
+ have_received(:get).with('https://target.my.com/api/v1/vk_groups.json',
38
+ params: { q: 'unfound' })
39
+ )
40
+ expect(result).to eq([])
32
41
  end
33
42
 
34
43
  it 'deletes object' do
35
- stub_request(:delete, 'https://target.my.com/api/v1/remarketing_context_phrases/53.json')
36
- .to_return(body: '[{ "success": true }]')
44
+ allow(MyTargetApi::NetClient).to(
45
+ receive(:delete).and_return(double(code: 200, body: '[{ "success": true }]', headers: {}))
46
+ )
37
47
 
38
- expect(
39
- subject.delete('https://target.my.com/api/v1/remarketing_context_phrases/53.json')
40
- ).to eq([{ 'success' => true }])
48
+ result = subject.delete('https://target.my.com/api/v1/remarketing_context_phrases/53.json')
49
+
50
+ expect(MyTargetApi::NetClient).to(
51
+ have_received(:delete).with(
52
+ 'https://target.my.com/api/v1/remarketing_context_phrases/53.json',
53
+ params: {}
54
+ )
55
+ )
56
+ expect(result).to eq([{ 'success' => true }])
41
57
  end
42
58
 
43
59
  it 'uploads raw content' do
44
- stub_request(:post, 'https://target.my.com/api/v2/search_phrases.json?name=list')
45
- .to_return(body: '{"id": 123, "name": "list"}')
46
-
47
- expect(
48
- subject.upload(
60
+ allow(MyTargetApi::NetClient).to(
61
+ receive(:post)
62
+ .and_return(double(code: 200, body: '{"id": 123, "name": "list"}', headers: {}))
63
+ )
64
+
65
+ result = subject.upload(
66
+ 'https://target.my.com/api/v2/search_phrases.json',
67
+ "phrase\nfirst\nsecond",
68
+ name: 'list'
69
+ )
70
+
71
+ expect(MyTargetApi::NetClient).to(
72
+ have_received(:post).with(
49
73
  'https://target.my.com/api/v2/search_phrases.json',
50
74
  "phrase\nfirst\nsecond",
51
- name: 'list'
75
+ 'Content-Type' => 'application/octet-stream',
76
+ params: { name: 'list' }
52
77
  )
53
- ).to eq('id' => 123, 'name' => 'list')
78
+ )
79
+ expect(result).to eq('id' => 123, 'name' => 'list')
54
80
  end
55
81
 
56
82
  it 'raises exception on bad statuses' do
@@ -58,7 +84,28 @@ describe MyTargetApi::Request do
58
84
  .to_return(body: 'Unknown resource', status: 404)
59
85
 
60
86
  expect { subject.get('https://target.my.com/api/v1/wrong_path.json') }
61
- .to raise_error(MyTargetApi::RequestError, 'Unknown resource')
87
+ .to raise_error(MyTargetApi::RequestError,
88
+ '404: Unknown resource. Inspect #params, #response and #original_exception'\
89
+ ' for more details')
90
+ end
91
+
92
+ it 'sets authorization header' do
93
+ allow(MyTargetApi::NetClient).to(
94
+ receive(:get).and_return(double(code: 200,
95
+ body: 'response body',
96
+ headers: {}))
97
+ )
98
+
99
+ request = MyTargetApi::Request.new(access_token: 'my_target_token')
100
+ request.get('https://target.my.com/api/v1/some_path.json')
101
+
102
+ expect(MyTargetApi::NetClient).to(
103
+ have_received(:get).with(
104
+ 'https://target.my.com/api/v1/some_path.json',
105
+ 'Authorization' => 'Bearer my_target_token',
106
+ params: {}
107
+ )
108
+ )
62
109
  end
63
110
  end
64
111
 
@@ -67,11 +114,61 @@ describe MyTargetApi::Request do
67
114
  let(:request) { MyTargetApi::Request.new(logger: logger) }
68
115
 
69
116
  it 'pass parameters by url in get' do
70
- stub_request(:get, 'https://target.my.com/api/v1/request.json')
71
- .to_return(body: '[]')
117
+ logger = double('Logger double', '<<': nil)
118
+ options = { logger: logger }
119
+ request = MyTargetApi::LogRequestParametersDecorator.new(
120
+ MyTargetApi::Request.new(options), options
121
+ )
122
+ allow(MyTargetApi::NetClient).to(
123
+ receive(:get).and_return(double(code: 200,
124
+ body: 'response body',
125
+ headers: {}))
126
+ )
72
127
 
73
- expect(logger).to(receive(:<<))
74
128
  request.get('https://target.my.com/api/v1/request.json')
129
+
130
+ expect(logger).to(have_received(:<<).with("method: Request#get\n"\
131
+ "url: https://target.my.com/api/v1/request.json\n"\
132
+ 'params: {}'))
133
+ expect(logger).to(have_received(:<<).with(<<~LOG))
134
+ HTTP Code: 200
135
+ HTTP Body:
136
+ response body
137
+ HTTP Headers: No headers
138
+ LOG
139
+ end
140
+
141
+ it '404' do
142
+ logger = double('Logger double', '<<': nil)
143
+ options = { logger: logger }
144
+ request = MyTargetApi::LogRequestParametersDecorator.new(
145
+ MyTargetApi::Request.new(options), options
146
+ )
147
+ allow(MyTargetApi::NetClient).to(
148
+ receive(:get).and_return(
149
+ double(
150
+ body: 'Unknown resource',
151
+ code: 404,
152
+ headers: { 'Header': 'Value' }
153
+ )
154
+ )
155
+ )
156
+
157
+ expect { request.get('https://target.my.com/api/v1/request.json') }
158
+ .to raise_error(MyTargetApi::RequestError,
159
+ '404: Unknown resource. Inspect #params, #response and #original_exception'\
160
+ ' for more details')
161
+
162
+ expect(logger).to(have_received(:<<).with("method: Request#get\n"\
163
+ "url: https://target.my.com/api/v1/request.json\n"\
164
+ 'params: {}'))
165
+ expect(logger).to(have_received(:<<).with(<<~LOG))
166
+ HTTP Code: 404
167
+ HTTP Body:
168
+ Unknown resource
169
+ HTTP Headers:
170
+ Header: Value
171
+ LOG
75
172
  end
76
173
  end
77
174
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: my_target_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - OneRetarget.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-27 00:00:00.000000000 Z
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -56,14 +56,14 @@ dependencies:
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '1.6'
59
+ version: 2.1.4
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '1.6'
66
+ version: 2.1.4
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: rake
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -110,14 +110,14 @@ dependencies:
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: 0.54.0
113
+ version: 0.89.1
114
114
  type: :development
115
115
  prerelease: false
116
116
  version_requirements: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - "~>"
119
119
  - !ruby/object:Gem::Version
120
- version: 0.54.0
120
+ version: 0.89.1
121
121
  - !ruby/object:Gem::Dependency
122
122
  name: webmock
123
123
  requirement: !ruby/object:Gem::Requirement
@@ -153,12 +153,15 @@ files:
153
153
  - LICENSE.txt
154
154
  - README.md
155
155
  - lib/my_target_api.rb
156
- - lib/my_target_api/connection_error.rb
156
+ - lib/my_target_api/log_request_parameters_decorator.rb
157
+ - lib/my_target_api/net_client.rb
157
158
  - lib/my_target_api/request.rb
158
159
  - lib/my_target_api/request_error.rb
159
160
  - lib/my_target_api/resource.rb
161
+ - lib/my_target_api/response_formatter.rb
160
162
  - lib/my_target_api/version.rb
161
163
  - my_target_api.gemspec
164
+ - spec/net_client_spec.rb
162
165
  - spec/request_spec.rb
163
166
  - spec/resource_spec.rb
164
167
  - spec/root_spec.rb
@@ -175,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
178
  requirements:
176
179
  - - ">="
177
180
  - !ruby/object:Gem::Version
178
- version: '0'
181
+ version: 2.4.0
179
182
  required_rubygems_version: !ruby/object:Gem::Requirement
180
183
  requirements:
181
184
  - - ">="
@@ -188,6 +191,7 @@ signing_key:
188
191
  specification_version: 4
189
192
  summary: Ruby client for myTarget API
190
193
  test_files:
194
+ - spec/net_client_spec.rb
191
195
  - spec/request_spec.rb
192
196
  - spec/resource_spec.rb
193
197
  - spec/root_spec.rb
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class MyTargetApi
4
- # Error class
5
- class ConnectionError < StandardError
6
-
7
- attr_reader :original_exception
8
-
9
- def initialize(exception)
10
- @original_exception = exception
11
- @exception = exception
12
- end
13
-
14
- def message
15
- @exception.message
16
- end
17
-
18
- end
19
- end