my_target_api 1.2.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +20 -15
- data/README.md +7 -7
- data/lib/my_target_api.rb +7 -7
- 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 +46 -46
- 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: '0999c662cc6ea8e0bcecc4249c884cf8b328a2e0'
|
4
|
+
data.tar.gz: 81fb3f024b641b089c2b5feeba1ab93ee4dac166
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: befab2c57b071a78282c872b875e66635f766a4a9e66b75911411962bc201371726a57a89c7312d3da7ac5468142be9e8a3f90e34f4b0864f878dd297f6d2f8f
|
7
|
+
data.tar.gz: 1fa4fe33765103406444fb2447c21cafb9ce15927857ae9065d4f593c4cca5171f8af45fd9e7b95c6ea947ac980e41240f39a3f7ba738a6baaaf4bb111ed52ab
|
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.0)
|
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.0'
|
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
|
@@ -24,19 +24,19 @@ class MyTargetApi
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def get_request(url, params)
|
27
|
-
request_object.get(url, params
|
27
|
+
request_object.get(url, params)
|
28
28
|
end
|
29
29
|
|
30
30
|
def post_request(url, params)
|
31
|
-
request_object.post(url, params
|
31
|
+
request_object.post(url, params)
|
32
32
|
end
|
33
33
|
|
34
34
|
def delete_request(url, params)
|
35
|
-
request_object.delete(url, params
|
35
|
+
request_object.delete(url, params)
|
36
36
|
end
|
37
37
|
|
38
38
|
def upload_request(url, content, params)
|
39
|
-
request_object.upload(url, content, params
|
39
|
+
request_object.upload(url, content, params)
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
@@ -44,7 +44,7 @@ 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.new(logger: options[:logger], access_token: access_token, headers: options[:headers])
|
48
48
|
end
|
49
49
|
|
50
50
|
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,40 +13,36 @@ 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
|
-
|
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')
|
45
|
+
)
|
49
46
|
end
|
50
47
|
|
51
48
|
process_response(response)
|
@@ -66,9 +63,9 @@ class MyTargetApi
|
|
66
63
|
end
|
67
64
|
|
68
65
|
def individual_body_parameters(params)
|
69
|
-
params.
|
70
|
-
|
71
|
-
end
|
66
|
+
params.transform_values do |value|
|
67
|
+
value.is_a?(Array) || value.is_a?(Hash) ? value.to_json : value
|
68
|
+
end
|
72
69
|
end
|
73
70
|
|
74
71
|
def query(params)
|
@@ -76,7 +73,11 @@ class MyTargetApi
|
|
76
73
|
end
|
77
74
|
|
78
75
|
def headers
|
79
|
-
|
76
|
+
if access_token
|
77
|
+
optional_headers.merge('Authorization' => "Bearer #{access_token}")
|
78
|
+
else
|
79
|
+
optional_headers
|
80
|
+
end
|
80
81
|
end
|
81
82
|
|
82
83
|
def process_response(response)
|
@@ -85,38 +86,33 @@ class MyTargetApi
|
|
85
86
|
response.body
|
86
87
|
end
|
87
88
|
|
88
|
-
def with_exception_handling
|
89
|
+
def with_exception_handling(params)
|
89
90
|
response = yield
|
90
|
-
|
91
|
+
log_response(response)
|
92
|
+
raise_with_params(params: params, response: response) if response.code >= 400
|
91
93
|
response
|
92
|
-
rescue
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
log("#{e.class.name} #{e.message}")
|
97
|
-
raise MyTargetApi::RequestError, e
|
98
|
-
rescue SocketError => e
|
99
|
-
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)
|
100
98
|
end
|
101
99
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
RestClient exception
|
106
|
-
Class: #{exception.class}
|
107
|
-
Message: #{exception.message}
|
108
|
-
HTTP Code: #{exception.http_code}
|
109
|
-
HTTP Body: #{exception.http_body}
|
110
|
-
HTTP headers: #{exception.http_headers}
|
111
|
-
LOG
|
100
|
+
def log_response(response)
|
101
|
+
log(ResponseFormatter.new(response).format)
|
102
|
+
end
|
112
103
|
|
113
|
-
|
104
|
+
def headers_to_string(headers)
|
105
|
+
headers.map do |name, value|
|
106
|
+
"#{name}: #{value}"
|
107
|
+
end.join("\n")
|
114
108
|
end
|
115
109
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
120
116
|
end
|
121
117
|
|
122
118
|
def log(message)
|
@@ -127,5 +123,9 @@ class MyTargetApi
|
|
127
123
|
options[:access_token]
|
128
124
|
end
|
129
125
|
|
126
|
+
def optional_headers
|
127
|
+
options[:headers] || {}
|
128
|
+
end
|
129
|
+
|
130
130
|
end
|
131
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.0
|
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-08-31 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
|