ddy_remote_resource 1.0.5 → 1.1.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 +4 -4
- data/lib/remote_resource/base.rb +1 -0
- data/lib/remote_resource/connection_options.rb +1 -1
- data/lib/remote_resource/request.rb +51 -24
- data/lib/remote_resource/response.rb +21 -11
- data/lib/remote_resource/version.rb +1 -1
- data/spec/lib/remote_resource/connection_options_spec.rb +5 -4
- data/spec/lib/remote_resource/request_spec.rb +33 -7
- data/spec/lib/remote_resource/response_spec.rb +33 -3
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9834a14e5c56cb3573cd70a5b29f928895baf53116926b219cf843f10a9c22df
|
4
|
+
data.tar.gz: bc8106a2ae149bcc1e185265d4cd49631a221f98aff93676c5c3fcec9e1833ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adb751faffb267b13f17b7645ab2690c262f7c3c9b7df8f46374afcf455f2f7beacb80b45bcff50489446e786df01ac1416b3d4816d7f4e0c67721079da52de6
|
7
|
+
data.tar.gz: d9e331a8342b281aebb2d07c087192dad0415c1aeab60d19966f9ae5c6eefd0880dce73002d757f57d004a8d9dbbb0ac381e612618333105645a3aa95937f1d4
|
data/lib/remote_resource/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module RemoteResource
|
2
2
|
class ConnectionOptions
|
3
3
|
|
4
|
-
AVAILABLE_OPTIONS = [:site, :headers, :default_headers, :version, :path_prefix, :path_postfix, :collection_prefix, :extension, :collection, :collection_name, :root_element].freeze
|
4
|
+
AVAILABLE_OPTIONS = [:site, :headers, :default_headers, :version, :path_prefix, :path_postfix, :collection_prefix, :extension, :collection, :collection_name, :root_element, :json_spec].freeze
|
5
5
|
|
6
6
|
attr_reader :base_class
|
7
7
|
|
@@ -84,12 +84,20 @@ module RemoteResource
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def attributes
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
if connection_options[:json_spec] == :json_api
|
88
|
+
if @attributes
|
89
|
+
{ data: { id: @attributes[:id], type: resource_klass.name.demodulize, attributes: @attributes.except(:id) } }
|
90
|
+
else
|
91
|
+
{ data: {} }
|
92
|
+
end
|
91
93
|
else
|
92
|
-
|
94
|
+
root_element = connection_options[:root_element]
|
95
|
+
|
96
|
+
if root_element.present?
|
97
|
+
{ root_element => @attributes }
|
98
|
+
else
|
99
|
+
@attributes || {}
|
100
|
+
end
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
@@ -114,25 +122,44 @@ module RemoteResource
|
|
114
122
|
|
115
123
|
def raise_http_error(request, response)
|
116
124
|
case response.try(:response_code)
|
117
|
-
when 301, 302, 303, 307 then
|
118
|
-
|
119
|
-
when
|
120
|
-
|
121
|
-
when
|
122
|
-
|
123
|
-
when
|
124
|
-
|
125
|
-
when
|
126
|
-
|
127
|
-
when
|
128
|
-
|
129
|
-
when
|
130
|
-
|
131
|
-
when
|
132
|
-
|
133
|
-
when
|
134
|
-
|
135
|
-
when
|
125
|
+
when 301, 302, 303, 307 then
|
126
|
+
raise RemoteResource::HTTPRedirectionError.new(request, response)
|
127
|
+
when 400 then
|
128
|
+
raise RemoteResource::HTTPBadRequest.new(request, response)
|
129
|
+
when 401 then
|
130
|
+
raise RemoteResource::HTTPUnauthorized.new(request, response)
|
131
|
+
when 403 then
|
132
|
+
raise RemoteResource::HTTPForbidden.new(request, response)
|
133
|
+
when 404 then
|
134
|
+
raise RemoteResource::HTTPNotFound.new(request, response)
|
135
|
+
when 405 then
|
136
|
+
raise RemoteResource::HTTPMethodNotAllowed.new(request, response)
|
137
|
+
when 406 then
|
138
|
+
raise RemoteResource::HTTPNotAcceptable.new(request, response)
|
139
|
+
when 408 then
|
140
|
+
raise RemoteResource::HTTPRequestTimeout.new(request, response)
|
141
|
+
when 409 then
|
142
|
+
raise RemoteResource::HTTPConflict.new(request, response)
|
143
|
+
when 410 then
|
144
|
+
raise RemoteResource::HTTPGone.new(request, response)
|
145
|
+
when 418 then
|
146
|
+
raise RemoteResource::HTTPTeapot.new(request, response)
|
147
|
+
when 444 then
|
148
|
+
raise RemoteResource::HTTPNoResponse.new(request, response)
|
149
|
+
when 494 then
|
150
|
+
raise RemoteResource::HTTPRequestHeaderTooLarge.new(request, response)
|
151
|
+
when 495 then
|
152
|
+
raise RemoteResource::HTTPCertError.new(request, response)
|
153
|
+
when 496 then
|
154
|
+
raise RemoteResource::HTTPNoCert.new(request, response)
|
155
|
+
when 497 then
|
156
|
+
raise RemoteResource::HTTPToHTTPS.new(request, response)
|
157
|
+
when 499 then
|
158
|
+
raise RemoteResource::HTTPClientClosedRequest.new(request, response)
|
159
|
+
when 400..499 then
|
160
|
+
raise RemoteResource::HTTPClientError.new(request, response)
|
161
|
+
when 500..599 then
|
162
|
+
raise RemoteResource::HTTPServerError.new(request, response)
|
136
163
|
else
|
137
164
|
raise RemoteResource::HTTPError.new(request, response)
|
138
165
|
end
|
@@ -44,19 +44,29 @@ module RemoteResource
|
|
44
44
|
|
45
45
|
def attributes
|
46
46
|
@attributes ||= begin
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
data
|
47
|
+
if @connection_options[:json_spec] == :json_api
|
48
|
+
data = parsed_body.fetch("data", {})
|
49
|
+
if data.is_a?(Array)
|
50
|
+
data.map { |row| row["attributes"].merge({ "id" => row["id"] }) }
|
51
|
+
elsif data.key?("attributes")
|
52
|
+
data["attributes"].merge({ "id" => data["id"] })
|
53
|
+
else
|
54
|
+
data
|
55
|
+
end
|
52
56
|
else
|
53
|
-
|
54
|
-
end
|
57
|
+
root_element = @connection_options[:root_element].to_s
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
if root_element.present?
|
60
|
+
data = parsed_body.try(:key?, root_element) && parsed_body[root_element]
|
61
|
+
else
|
62
|
+
data = parsed_body
|
63
|
+
end
|
64
|
+
|
65
|
+
if data.is_a?(Array)
|
66
|
+
data
|
67
|
+
else
|
68
|
+
data.presence || {}
|
69
|
+
end
|
60
70
|
end
|
61
71
|
end
|
62
72
|
end
|
@@ -24,7 +24,7 @@ RSpec.describe RemoteResource::ConnectionOptions do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:dummy_class) { RemoteResource::ConnectionOptionsDummy }
|
27
|
-
let(:dummy)
|
27
|
+
let(:dummy) { dummy_class.new }
|
28
28
|
|
29
29
|
let(:connection_options) { described_class.new dummy_class }
|
30
30
|
|
@@ -59,8 +59,8 @@ RSpec.describe RemoteResource::ConnectionOptions do
|
|
59
59
|
describe '#merge' do
|
60
60
|
let(:custom_connection_options) do
|
61
61
|
{
|
62
|
-
site:
|
63
|
-
version:
|
62
|
+
site: 'https://dummy.foobar.com',
|
63
|
+
version: '/api/v2',
|
64
64
|
root_element: :test_dummy_api
|
65
65
|
}
|
66
66
|
end
|
@@ -91,7 +91,8 @@ RSpec.describe RemoteResource::ConnectionOptions do
|
|
91
91
|
collection_prefix: '/parent/:parent_id',
|
92
92
|
collection: true,
|
93
93
|
collection_name: nil,
|
94
|
-
root_element: :test_dummy
|
94
|
+
root_element: :test_dummy,
|
95
|
+
json_spec: nil
|
95
96
|
}
|
96
97
|
end
|
97
98
|
|
@@ -18,10 +18,10 @@ RSpec.describe RemoteResource::Request do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
let(:dummy_class) { RemoteResource::RequestDummy }
|
21
|
-
let(:dummy)
|
21
|
+
let(:dummy) { dummy_class.new id: '12' }
|
22
22
|
|
23
|
-
let(:resource)
|
24
|
-
let(:http_action)
|
23
|
+
let(:resource) { dummy_class }
|
24
|
+
let(:http_action) { :get }
|
25
25
|
let(:connection_options) { {} }
|
26
26
|
let(:attributes) do
|
27
27
|
{ name: 'Mies' }
|
@@ -68,6 +68,7 @@ RSpec.describe RemoteResource::Request do
|
|
68
68
|
|
69
69
|
let(:block_connection_options) do
|
70
70
|
{
|
71
|
+
json_spec: 'From .with_connection_options',
|
71
72
|
root_element: 'From .with_connection_options',
|
72
73
|
version: 'From .with_connection_options',
|
73
74
|
path_prefix: 'From .with_connection_options'
|
@@ -85,6 +86,7 @@ RSpec.describe RemoteResource::Request do
|
|
85
86
|
{
|
86
87
|
site: 'From Klass.site',
|
87
88
|
root_element: 'From connection_options[]',
|
89
|
+
json_spec: 'From .with_connection_options',
|
88
90
|
version: 'From .with_connection_options',
|
89
91
|
path_prefix: 'From .with_connection_options',
|
90
92
|
path_postfix: 'From connection_options[]',
|
@@ -270,7 +272,7 @@ RSpec.describe RemoteResource::Request do
|
|
270
272
|
let(:expected_request_url) { '' }
|
271
273
|
|
272
274
|
it 'raises the RemoteResource::HTTPMethodUnsupported error' do
|
273
|
-
expect{ request.perform }.to raise_error RemoteResource::HTTPMethodUnsupported, 'Requested HTTP method=foo is NOT supported, the HTTP action MUST be a supported HTTP action=get, put, patch, post, delete'
|
275
|
+
expect { request.perform }.to raise_error RemoteResource::HTTPMethodUnsupported, 'Requested HTTP method=foo is NOT supported, the HTTP action MUST be a supported HTTP action=get, put, patch, post, delete'
|
274
276
|
end
|
275
277
|
end
|
276
278
|
end
|
@@ -367,7 +369,7 @@ RSpec.describe RemoteResource::Request do
|
|
367
369
|
|
368
370
|
context 'when connection_options does NOT include collection_options' do
|
369
371
|
it 'raises error' do
|
370
|
-
expect{ request.request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
|
372
|
+
expect { request.request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
|
371
373
|
end
|
372
374
|
end
|
373
375
|
end
|
@@ -473,6 +475,30 @@ RSpec.describe RemoteResource::Request do
|
|
473
475
|
end
|
474
476
|
end
|
475
477
|
end
|
478
|
+
|
479
|
+
context 'when connection_options[:json_spec] == :json_api' do
|
480
|
+
let(:connection_options) do
|
481
|
+
{ json_spec: :json_api }
|
482
|
+
end
|
483
|
+
|
484
|
+
let(:attributes) do
|
485
|
+
{ id: 1, name: 'Mies', featured: true, labels: [1, '2', 'three'] }
|
486
|
+
end
|
487
|
+
|
488
|
+
it 'returns the given attributes wrapped in the json api spec' do
|
489
|
+
expect(request.attributes).to eql({ data: { id: 1, type: "RequestDummy", attributes: { name: 'Mies', featured: true, labels: [1, '2', 'three'] } } })
|
490
|
+
end
|
491
|
+
|
492
|
+
context 'and there are NO given attributes' do
|
493
|
+
let(:attributes) do
|
494
|
+
nil
|
495
|
+
end
|
496
|
+
|
497
|
+
it 'returns nil wrapped in the connection_options[:root_element]' do
|
498
|
+
expect(request.attributes).to eql({ data: {} })
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
476
502
|
end
|
477
503
|
|
478
504
|
describe '#headers' do
|
@@ -506,7 +532,7 @@ RSpec.describe RemoteResource::Request do
|
|
506
532
|
end
|
507
533
|
|
508
534
|
before { RemoteResource::Base.global_headers = { 'User-Agent' => 'From RemoteResource::Base.global_headers', 'X-Locale' => 'From RemoteResource::Base.global_headers' } }
|
509
|
-
after
|
535
|
+
after { RemoteResource::Base.global_headers = nil }
|
510
536
|
|
511
537
|
it 'returns the default headers while overwriting the headers according to the correct precedence' do
|
512
538
|
expect(request.headers).to eql expected_headers
|
@@ -562,7 +588,7 @@ RSpec.describe RemoteResource::Request do
|
|
562
588
|
|
563
589
|
describe '#raise_http_error' do
|
564
590
|
let(:connection_response) { instance_double(Typhoeus::Response, request: instance_double(Typhoeus::Request)) }
|
565
|
-
let(:response)
|
591
|
+
let(:response) { RemoteResource::Response.new(connection_response, connection_options) }
|
566
592
|
|
567
593
|
context 'when the response code is 301, 302, 303 or 307' do
|
568
594
|
response_codes = [301, 302, 303, 307]
|
@@ -14,14 +14,14 @@ RSpec.describe RemoteResource::Response do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
let(:dummy_class) { RemoteResource::ResponseDummy }
|
17
|
-
let(:dummy)
|
17
|
+
let(:dummy) { dummy_class.new(id: '12') }
|
18
18
|
|
19
19
|
let(:connection_options) do
|
20
20
|
{ collection: true }
|
21
21
|
end
|
22
|
-
let(:request)
|
22
|
+
let(:request) { RemoteResource::Request.new(dummy_class, :post, { name: 'Mies' }, connection_options) }
|
23
23
|
let(:connection_response) { Typhoeus::Response.new(mock: true, code: 201, body: { id: 12, name: 'Mies' }.to_json, headers: { 'Content-Type' => 'application/json', 'Server' => 'nginx/1.4.6 (Ubuntu)' }) }
|
24
|
-
let(:connection_request)
|
24
|
+
let(:connection_request) { Typhoeus::Request.new('http://www.foobar.com/response_dummies.json', method: :post, body: { name: 'Mies' }.to_json, headers: { 'Content-Type' => 'application/json' }) }
|
25
25
|
|
26
26
|
let(:response) { described_class.new(connection_response, connection_options.merge(request: request, connection_request: connection_request)) }
|
27
27
|
|
@@ -156,6 +156,36 @@ RSpec.describe RemoteResource::Response do
|
|
156
156
|
expect(response.attributes).to eql({})
|
157
157
|
end
|
158
158
|
end
|
159
|
+
|
160
|
+
context 'with the json_api spec' do
|
161
|
+
let(:connection_options) do
|
162
|
+
{ root_element: :data, json_spec: :json_api }
|
163
|
+
end
|
164
|
+
|
165
|
+
context "single response" do
|
166
|
+
let(:connection_response) { Typhoeus::Response.new(mock: true, code: 201, body: { data: { id: 12, attributes: { name: 'Mies' } } }.to_json, headers: { 'Content-Type' => 'application/json', 'Server' => 'nginx/1.4.6 (Ubuntu)' }) }
|
167
|
+
|
168
|
+
it 'parses the attributes from the nested hash' do
|
169
|
+
expect(response.attributes).to eql({ 'id' => 12, 'name' => 'Mies' })
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "empty response" do
|
174
|
+
let(:connection_response) { Typhoeus::Response.new(mock: true, code: 204, body: {}.to_json, headers: { 'Content-Type' => 'application/json', 'Server' => 'nginx/1.4.6 (Ubuntu)' }) }
|
175
|
+
|
176
|
+
it 'parses the attributes from the nested hash' do
|
177
|
+
expect(response.attributes).to eql({})
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "collection response" do
|
182
|
+
let(:connection_response) { Typhoeus::Response.new(mock: true, code: 201, body: { data: [{ id: 12, attributes: { name: 'Mies' } }] }.to_json, headers: { 'Content-Type' => 'application/json', 'Server' => 'nginx/1.4.6 (Ubuntu)' }) }
|
183
|
+
|
184
|
+
it 'parses the attributes from the nested hash' do
|
185
|
+
expect(response.attributes).to eql(['id' => 12, 'name' => 'Mies'])
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
159
189
|
end
|
160
190
|
|
161
191
|
describe '#errors' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddy_remote_resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan van der Pas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -206,22 +206,22 @@ dependencies:
|
|
206
206
|
name: typhoeus
|
207
207
|
requirement: !ruby/object:Gem::Requirement
|
208
208
|
requirements:
|
209
|
-
- - "~>"
|
210
|
-
- !ruby/object:Gem::Version
|
211
|
-
version: '0.7'
|
212
209
|
- - ">="
|
213
210
|
- !ruby/object:Gem::Version
|
214
211
|
version: 0.7.0
|
212
|
+
- - "~>"
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0.7'
|
215
215
|
type: :runtime
|
216
216
|
prerelease: false
|
217
217
|
version_requirements: !ruby/object:Gem::Requirement
|
218
218
|
requirements:
|
219
|
-
- - "~>"
|
220
|
-
- !ruby/object:Gem::Version
|
221
|
-
version: '0.7'
|
222
219
|
- - ">="
|
223
220
|
- !ruby/object:Gem::Version
|
224
221
|
version: 0.7.0
|
222
|
+
- - "~>"
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: '0.7'
|
225
225
|
- !ruby/object:Gem::Dependency
|
226
226
|
name: request_store
|
227
227
|
requirement: !ruby/object:Gem::Requirement
|
@@ -319,8 +319,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
319
319
|
- !ruby/object:Gem::Version
|
320
320
|
version: '0'
|
321
321
|
requirements: []
|
322
|
-
|
323
|
-
rubygems_version: 2.7.7
|
322
|
+
rubygems_version: 3.0.2
|
324
323
|
signing_key:
|
325
324
|
specification_version: 4
|
326
325
|
summary: RemoteResource, a gem to use resources with REST services.
|