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 +4 -4
- data/Gemfile.lock +20 -15
- data/README.md +7 -7
- data/lib/my_target_api.rb +10 -3
- data/lib/my_target_api/log_request_parameters_decorator.rb +55 -0
- data/lib/my_target_api/net_client.rb +80 -0
- data/lib/my_target_api/request.rb +45 -47
- data/lib/my_target_api/request_error.rb +9 -15
- data/lib/my_target_api/response_formatter.rb +38 -0
- data/lib/my_target_api/version.rb +1 -1
- data/my_target_api.gemspec +3 -2
- data/spec/net_client_spec.rb +120 -0
- data/spec/request_spec.rb +123 -26
- metadata +12 -8
- data/lib/my_target_api/connection_error.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4254318b97e9d1f594438694a31a6511ea9461fc
|
4
|
+
data.tar.gz: 69e005cf224551553abdc2c047d84b278a3f3e70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08db4857b6fb49cacdc2050356b43aa94b3998fb2a8f0d31fc133e12554b07d190e0a370363b9b8bc5dfa88a53717c91b449b0ba5de5d1254dab65bfd3e93c38'
|
7
|
+
data.tar.gz: '08966200b98a7df2bfc4fee600650072ee52343e5ff3f83b987a450cd915901ee88b2273aea35e67b6a40f66e50020a75ee68ac35e66b713f14207d5aa12fe3b'
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
my_target_api (
|
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.
|
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.
|
28
|
-
parser (2.
|
29
|
-
ast (~> 2.4.
|
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.
|
52
|
+
rubocop (0.89.1)
|
52
53
|
parallel (~> 1.10)
|
53
|
-
parser (>= 2.
|
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 (
|
58
|
-
|
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.
|
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.
|
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.
|
82
|
+
rubocop (~> 0.89.1)
|
78
83
|
webmock (~> 2.3.2, >= 2.3.2)
|
79
84
|
|
80
85
|
BUNDLED WITH
|
81
|
-
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', '~>
|
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
|
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
|
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
|
|
data/lib/my_target_api.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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.
|
72
|
-
|
73
|
-
end
|
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
|
-
|
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
|
-
|
91
|
+
log_response(response)
|
92
|
+
raise_with_params(params: params, response: response) if response.code >= 400
|
93
93
|
response
|
94
|
-
rescue
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
105
|
-
|
106
|
-
|
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
|
-
|
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
|
119
|
-
|
120
|
-
|
121
|
-
|
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(
|
10
|
-
@
|
11
|
-
|
12
|
-
|
9
|
+
def initialize(params:, original_exception: nil, response: nil)
|
10
|
+
@params = params
|
11
|
+
@response = response
|
12
|
+
@original_exception = original_exception
|
13
13
|
|
14
|
-
|
14
|
+
message =
|
15
|
+
"#{(response ? "#{response.code}: #{response.body}. " : '')}"\
|
16
|
+
'Inspect #params, #response and #original_exception for more details'
|
15
17
|
|
16
|
-
|
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
|
data/my_target_api.gemspec
CHANGED
@@ -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.
|
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.
|
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¶m2[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¶m2%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¶m2%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
|
data/spec/request_spec.rb
CHANGED
@@ -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
|
-
|
20
|
-
.
|
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(
|
23
|
-
.
|
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
|
-
|
28
|
-
.
|
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(
|
31
|
-
.
|
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
|
-
|
36
|
-
.
|
44
|
+
allow(MyTargetApi::NetClient).to(
|
45
|
+
receive(:delete).and_return(double(code: 200, body: '[{ "success": true }]', headers: {}))
|
46
|
+
)
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
).to
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
75
|
+
'Content-Type' => 'application/octet-stream',
|
76
|
+
params: { name: 'list' }
|
52
77
|
)
|
53
|
-
)
|
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,
|
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
|
-
|
71
|
-
|
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:
|
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:
|
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:
|
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:
|
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.
|
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.
|
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/
|
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:
|
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
|