rdstation-ruby-client 1.2.0 → 2.3.0
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 +5 -5
- data/.github/ISSUE_TEMPLATE/rdsm-ruby-client-issue-template.md +49 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +163 -0
- data/README.md +243 -43
- data/lib/rdstation-ruby-client.rb +6 -0
- data/lib/rdstation.rb +19 -0
- data/lib/rdstation/api_response.rb +3 -3
- data/lib/rdstation/authentication.rb +32 -3
- data/lib/rdstation/authorization.rb +24 -0
- data/lib/rdstation/builder/field.rb +70 -0
- data/lib/rdstation/client.rb +17 -70
- data/lib/rdstation/contacts.rb +21 -16
- data/lib/rdstation/error.rb +22 -15
- data/lib/rdstation/error/format.rb +21 -3
- data/lib/rdstation/error/formatter.rb +53 -7
- data/lib/rdstation/error_handler.rb +29 -26
- data/lib/rdstation/error_handler/bad_request.rb +30 -0
- data/lib/rdstation/error_handler/unauthorized.rb +17 -9
- data/lib/rdstation/events.rb +7 -19
- data/lib/rdstation/fields.rb +31 -7
- data/lib/rdstation/retryable_request.rb +35 -0
- data/lib/rdstation/version.rb +1 -1
- data/lib/rdstation/webhooks.rb +25 -17
- data/rdstation-ruby-client.gemspec +4 -1
- data/spec/lib/rdstation-ruby-client_spec.rb +1 -1
- data/spec/lib/rdstation/api_response_spec.rb +34 -0
- data/spec/lib/rdstation/authentication_spec.rb +164 -0
- data/spec/lib/rdstation/authorization_spec.rb +24 -0
- data/spec/lib/rdstation/builder/field_spec.rb +69 -0
- data/spec/lib/rdstation/client_spec.rb +37 -0
- data/spec/lib/rdstation/contacts_spec.rb +54 -41
- data/spec/lib/rdstation/error/format_spec.rb +46 -0
- data/spec/lib/rdstation/error/formatter_spec.rb +83 -0
- data/spec/lib/rdstation/error_handler/unauthorized_spec.rb +0 -29
- data/spec/lib/rdstation/error_handler_spec.rb +153 -26
- data/spec/lib/rdstation/events_spec.rb +20 -9
- data/spec/lib/rdstation/fields_spec.rb +10 -3
- data/spec/lib/rdstation/retryable_request_spec.rb +142 -0
- data/spec/lib/rdstation/webhooks_spec.rb +41 -13
- data/spec/lib/rdstation_spec.rb +18 -0
- metadata +40 -13
- data/Gemfile.lock +0 -59
- data/lib/rdstation/error_handler/default.rb +0 -15
- data/lib/rdstation/error_handler/resource_not_found.rb +0 -24
- data/spec/lib/rdstation/error_handler/default_spec.rb +0 -14
- data/spec/lib/rdstation/error_handler/resource_not_found_spec.rb +0 -54
@@ -52,5 +52,51 @@ RSpec.describe RDStation::Error::Format do
|
|
52
52
|
expect(result).to eq(RDStation::Error::Format::ARRAY_OF_HASHES)
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
context 'when receives a mixed type of errors' do
|
57
|
+
let(:errors) do
|
58
|
+
{
|
59
|
+
'label': {
|
60
|
+
'pt-BR': [
|
61
|
+
{
|
62
|
+
'error_type': 'CANNOT_BE_BLANK',
|
63
|
+
'error_message': 'cannot be blank'
|
64
|
+
}
|
65
|
+
]
|
66
|
+
},
|
67
|
+
'api_identifier': [
|
68
|
+
{
|
69
|
+
'error_type': 'CANNOT_BE_BLANK',
|
70
|
+
'error_message': 'cannot be blank'
|
71
|
+
}
|
72
|
+
]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns the HASH_OF_MULTIPLE_TYPES format' do
|
77
|
+
result = error_format.format
|
78
|
+
expect(result).to eq(RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when receives a hash of hashes errors' do
|
83
|
+
let(:errors) do
|
84
|
+
{
|
85
|
+
label: {
|
86
|
+
'pt-BR': [
|
87
|
+
{
|
88
|
+
'error_type': 'CANNOT_BE_BLANK',
|
89
|
+
'error_message': 'cannot be blank'
|
90
|
+
}
|
91
|
+
]
|
92
|
+
}
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns the HASH_OF_MULTILINGUAL format' do
|
97
|
+
result = error_format.format
|
98
|
+
expect(result).to eq(RDStation::Error::Format::HASH_OF_HASHES)
|
99
|
+
end
|
100
|
+
end
|
55
101
|
end
|
56
102
|
end
|
@@ -132,5 +132,88 @@ RSpec.describe RDStation::Error::Formatter do
|
|
132
132
|
expect(result).to eq(expected_result)
|
133
133
|
end
|
134
134
|
end
|
135
|
+
|
136
|
+
context 'when receives a hash of multiple type errors' do
|
137
|
+
let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES) }
|
138
|
+
|
139
|
+
let(:error_response) do
|
140
|
+
{
|
141
|
+
'errors' => {
|
142
|
+
'label' => {
|
143
|
+
'pt-BR' => [
|
144
|
+
{
|
145
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
146
|
+
'error_message' => 'cannot be blank'
|
147
|
+
}
|
148
|
+
]
|
149
|
+
},
|
150
|
+
'api_identifier' => [
|
151
|
+
{
|
152
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
153
|
+
'error_message' => 'cannot be blank'
|
154
|
+
}
|
155
|
+
]
|
156
|
+
}
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
let(:error_formatter) { described_class.new(error_response) }
|
161
|
+
|
162
|
+
let(:expected_result) do
|
163
|
+
[
|
164
|
+
{
|
165
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
166
|
+
'error_message' => 'cannot be blank',
|
167
|
+
'path' => 'body.label.pt-BR'
|
168
|
+
},
|
169
|
+
{
|
170
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
171
|
+
'error_message' => 'cannot be blank',
|
172
|
+
'path' => 'body.api_identifier'
|
173
|
+
}
|
174
|
+
]
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns an array of errors' do
|
178
|
+
result = error_formatter.to_array
|
179
|
+
expect(result).to eq(expected_result)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'when receives a hash of hashes type errors' do
|
184
|
+
let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_HASHES) }
|
185
|
+
|
186
|
+
let(:error_response) do
|
187
|
+
{
|
188
|
+
'errors' => {
|
189
|
+
'label' => {
|
190
|
+
'pt-BR' => [
|
191
|
+
{
|
192
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
193
|
+
'error_message' => 'cannot be blank'
|
194
|
+
}
|
195
|
+
]
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
end
|
200
|
+
|
201
|
+
let(:error_formatter) { described_class.new(error_response) }
|
202
|
+
|
203
|
+
let(:expected_result) do
|
204
|
+
[
|
205
|
+
{
|
206
|
+
'error_type' => 'CANNOT_BE_BLANK',
|
207
|
+
'error_message' => 'cannot be blank',
|
208
|
+
'path' => 'body.label.pt-BR'
|
209
|
+
}
|
210
|
+
]
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'returns an array of errors' do
|
214
|
+
result = error_formatter.to_array
|
215
|
+
expect(result).to eq(expected_result)
|
216
|
+
end
|
217
|
+
end
|
135
218
|
end
|
136
219
|
end
|
@@ -21,34 +21,5 @@ RSpec.describe RDStation::ErrorHandler::Unauthorized do
|
|
21
21
|
end.to raise_error(RDStation::Error::Unauthorized, 'Error Message')
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
context 'when none of the errors are unauthorized errors' do
|
26
|
-
let(:errors) do
|
27
|
-
[
|
28
|
-
{
|
29
|
-
'error_message' => 'Error Message',
|
30
|
-
'error_type' => 'RANDOM_ERROR_TYPE'
|
31
|
-
},
|
32
|
-
{
|
33
|
-
'error_message' => 'Another Error Message',
|
34
|
-
'error_type' => 'ANOTHER_RANDOM_ERROR_TYPE'
|
35
|
-
}
|
36
|
-
]
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'does not raise an Unauthorized error' do
|
40
|
-
result = unauthorized_error.raise_error
|
41
|
-
expect(result).to be_nil
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'when there are no errors' do
|
46
|
-
let(:errors) { [] }
|
47
|
-
|
48
|
-
it 'does not raise an Unauthorized error' do
|
49
|
-
result = unauthorized_error.raise_error
|
50
|
-
expect(result).to be_nil
|
51
|
-
end
|
52
|
-
end
|
53
24
|
end
|
54
25
|
end
|
@@ -4,45 +4,172 @@ RSpec.describe RDStation::ErrorHandler do
|
|
4
4
|
describe '#raise_errors' do
|
5
5
|
subject(:error_handler) { described_class.new(error_response) }
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
let(:array_of_errors) do
|
8
|
+
[
|
9
|
+
{
|
10
|
+
'error_type' => 'ERROR_TYPE',
|
11
|
+
'error_message' => 'Error Message',
|
12
|
+
'headers' => { 'error' => 'header' },
|
13
|
+
'http_status' => http_status,
|
14
|
+
'body' => {
|
12
15
|
'errors' => {
|
13
|
-
'error_type' => '
|
16
|
+
'error_type' => 'ERROR_TYPE',
|
14
17
|
'error_message' => 'Error Message'
|
15
18
|
}
|
16
|
-
}
|
17
|
-
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:error_response) do
|
25
|
+
OpenStruct.new(
|
26
|
+
code: http_status,
|
27
|
+
headers: { 'error' => 'header' },
|
28
|
+
body: {
|
29
|
+
'errors' => {
|
30
|
+
'error_type' => 'ERROR_TYPE',
|
31
|
+
'error_message' => 'Error Message'
|
32
|
+
}
|
33
|
+
}.to_json
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with an error 400' do
|
38
|
+
let(:http_status) { 400 }
|
39
|
+
|
40
|
+
let(:bad_request_handler) { instance_double(RDStation::ErrorHandler::BadRequest, raise_error: 'raised error') }
|
41
|
+
|
42
|
+
before do
|
43
|
+
allow(RDStation::ErrorHandler::BadRequest).to receive(:new).with(array_of_errors).and_return(bad_request_handler)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'calls the bad request error handler' do
|
47
|
+
error_handler.raise_error
|
48
|
+
expect(bad_request_handler).to have_received(:raise_error)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'with an error 401' do
|
53
|
+
let(:http_status) { 401 }
|
54
|
+
|
55
|
+
let(:unauthorized_handler) { instance_double(RDStation::ErrorHandler::Unauthorized, raise_error: 'raised error') }
|
56
|
+
|
57
|
+
before do
|
58
|
+
allow(RDStation::ErrorHandler::Unauthorized).to receive(:new).with(array_of_errors).and_return(unauthorized_handler)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'calls the unauthorized error handler' do
|
62
|
+
error_handler.raise_error
|
63
|
+
expect(unauthorized_handler).to have_received(:raise_error)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with an error 403' do
|
68
|
+
let(:http_status) { 403 }
|
69
|
+
|
70
|
+
it 'raises a forbidden error' do
|
71
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::Forbidden, 'Error Message')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with an error 404' do
|
76
|
+
let(:http_status) { 404 }
|
77
|
+
|
78
|
+
it 'raises a not found error' do
|
79
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotFound, 'Error Message')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with an error 405' do
|
84
|
+
let(:http_status) { 405 }
|
85
|
+
|
86
|
+
it 'raises a method not allowed error' do
|
87
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::MethodNotAllowed, 'Error Message')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with an error 406' do
|
92
|
+
let(:http_status) { 406 }
|
93
|
+
|
94
|
+
it 'raises a not acceptable error' do
|
95
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotAcceptable, 'Error Message')
|
18
96
|
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'with an error 409' do
|
100
|
+
let(:http_status) { 409 }
|
19
101
|
|
20
|
-
it 'raises
|
21
|
-
expect { error_handler.
|
102
|
+
it 'raises a conflict error' do
|
103
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::Conflict, 'Error Message')
|
22
104
|
end
|
23
105
|
end
|
24
106
|
|
25
|
-
context '
|
107
|
+
context 'with an error 415' do
|
108
|
+
let(:http_status) { 415 }
|
109
|
+
|
110
|
+
it 'raises an unsupported media type error' do
|
111
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnsupportedMediaType, 'Error Message')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with an error 422' do
|
116
|
+
let(:http_status) { 422 }
|
117
|
+
|
118
|
+
it 'raises an unprocessable entity error' do
|
119
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnprocessableEntity, 'Error Message')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with an error 500' do
|
124
|
+
let(:http_status) { 500 }
|
125
|
+
|
126
|
+
it 'raises an internal server error' do
|
127
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::InternalServerError, 'Error Message')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with an error 501' do
|
132
|
+
let(:http_status) { 501 }
|
133
|
+
|
134
|
+
it 'raises a not implemented error' do
|
135
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::NotImplemented, 'Error Message')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with an error 502' do
|
140
|
+
let(:http_status) { 502 }
|
141
|
+
|
142
|
+
it 'raises a bad gateway error' do
|
143
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::BadGateway, 'Error Message')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with an error 503' do
|
148
|
+
let(:http_status) { 503 }
|
149
|
+
|
150
|
+
it 'raises a service unavailable error' do
|
151
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServiceUnavailable, 'Error Message')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
context 'with 5xx error' do
|
155
|
+
let(:http_status) { 505 }
|
156
|
+
|
157
|
+
it 'raises a server error' do
|
158
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServerError, 'Error Message')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "when response body is not JSON-parseable" do
|
26
163
|
let(:error_response) do
|
27
164
|
OpenStruct.new(
|
28
|
-
code:
|
29
|
-
headers: { '
|
30
|
-
body:
|
31
|
-
'errors' => {
|
32
|
-
'error_type' => 'UNRECOGNIZED_ERROR_TYPE',
|
33
|
-
'error_message' => 'Error Message'
|
34
|
-
}
|
35
|
-
}.to_json
|
165
|
+
code: 502,
|
166
|
+
headers: { 'error' => 'header' },
|
167
|
+
body: '<html><body>HTML error response</body></html>'
|
36
168
|
)
|
37
169
|
end
|
38
170
|
|
39
|
-
it 'raises the
|
40
|
-
expect { error_handler.
|
41
|
-
expect(error.details).to be
|
42
|
-
expect(error.headers).to be
|
43
|
-
expect(error.body).to be
|
44
|
-
expect(error.http_status).to be
|
45
|
-
end
|
171
|
+
it 'raises the correct error' do
|
172
|
+
expect { error_handler.raise_error }.to raise_error(RDStation::Error::BadGateway, '<html><body>HTML error response</body></html>')
|
46
173
|
end
|
47
174
|
end
|
48
175
|
end
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe RDStation::Events do
|
4
|
-
let(:
|
5
|
-
let(:
|
6
|
-
let(:
|
4
|
+
let(:valid_access_token) { 'valid_access_token' }
|
5
|
+
let(:invalid_access_token) { 'invalid_access_token' }
|
6
|
+
let(:expired_access_token) { 'expired_access_token' }
|
7
7
|
|
8
|
-
let(:event_with_valid_token)
|
9
|
-
|
10
|
-
|
8
|
+
let(:event_with_valid_token) do
|
9
|
+
described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
|
10
|
+
end
|
11
|
+
let(:event_with_expired_token) do
|
12
|
+
described_class.new(authorization: RDStation::Authorization.new(access_token: expired_access_token))
|
13
|
+
end
|
14
|
+
let(:event_with_invalid_token) do
|
15
|
+
described_class.new(authorization: RDStation::Authorization.new(access_token: invalid_access_token))
|
16
|
+
end
|
11
17
|
|
12
18
|
let(:events_endpoint) { 'https://api.rd.services/platform/events' }
|
13
19
|
|
@@ -45,21 +51,21 @@ RSpec.describe RDStation::Events do
|
|
45
51
|
|
46
52
|
let(:valid_headers) do
|
47
53
|
{
|
48
|
-
'Authorization' => "Bearer #{
|
54
|
+
'Authorization' => "Bearer #{valid_access_token}",
|
49
55
|
'Content-Type' => 'application/json'
|
50
56
|
}
|
51
57
|
end
|
52
58
|
|
53
59
|
let(:invalid_token_headers) do
|
54
60
|
{
|
55
|
-
'Authorization' => "Bearer #{
|
61
|
+
'Authorization' => "Bearer #{invalid_access_token}",
|
56
62
|
'Content-Type' => 'application/json'
|
57
63
|
}
|
58
64
|
end
|
59
65
|
|
60
66
|
let(:expired_token_headers) do
|
61
67
|
{
|
62
|
-
'Authorization' => "Bearer #{
|
68
|
+
'Authorization' => "Bearer #{expired_access_token}",
|
63
69
|
'Content-Type' => 'application/json'
|
64
70
|
}
|
65
71
|
end
|
@@ -102,6 +108,11 @@ RSpec.describe RDStation::Events do
|
|
102
108
|
}
|
103
109
|
end
|
104
110
|
|
111
|
+
it 'calls retryable_request' do
|
112
|
+
expect(event_with_valid_token).to receive(:retryable_request)
|
113
|
+
event_with_valid_token.create({})
|
114
|
+
end
|
115
|
+
|
105
116
|
context 'with a valid auth token' do
|
106
117
|
before do
|
107
118
|
stub_request(:post, events_endpoint)
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe RDStation::Fields do
|
4
|
-
let(:
|
5
|
-
let(:rdstation_fields_with_valid_token)
|
4
|
+
let(:valid_access_token) { 'valid_access_token' }
|
5
|
+
let(:rdstation_fields_with_valid_token) do
|
6
|
+
described_class.new(authorization: RDStation::Authorization.new(access_token: valid_access_token))
|
7
|
+
end
|
6
8
|
|
7
9
|
let(:valid_headers) do
|
8
10
|
{
|
9
|
-
'Authorization' => "Bearer #{
|
11
|
+
'Authorization' => "Bearer #{valid_access_token}",
|
10
12
|
'Content-Type' => 'application/json'
|
11
13
|
}
|
12
14
|
end
|
@@ -36,6 +38,11 @@ RSpec.describe RDStation::Fields do
|
|
36
38
|
}
|
37
39
|
end
|
38
40
|
|
41
|
+
it 'calls retryable_request' do
|
42
|
+
expect(rdstation_fields_with_valid_token).to receive(:retryable_request)
|
43
|
+
rdstation_fields_with_valid_token.all
|
44
|
+
end
|
45
|
+
|
39
46
|
context 'with a valid auth token' do
|
40
47
|
before do
|
41
48
|
stub_request(:get, fields_endpoint)
|