ddy_remote_resource 1.0.5 → 1.2.1
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/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/lib/remote_resource/base.rb +1 -0
- data/lib/remote_resource/connection_options.rb +1 -1
- data/lib/remote_resource/request.rb +66 -26
- data/lib/remote_resource/response.rb +25 -11
- data/lib/remote_resource/version.rb +1 -1
- data/remote_resource.gemspec +7 -7
- data/spec/integration/create_spec.rb +3 -3
- data/spec/integration/save_spec.rb +4 -4
- data/spec/lib/remote_resource/connection_options_spec.rb +5 -4
- data/spec/lib/remote_resource/request_spec.rb +76 -13
- data/spec/lib/remote_resource/response_spec.rb +33 -3
- data/spec/lib/remote_resource/version_spec.rb +1 -3
- metadata +17 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 72cede4abb216272f1f22c2e8c2509bc832a77ecfc1b10435c462206f56294de
|
|
4
|
+
data.tar.gz: d4fb9fa5d7515de365d5115e9652c27ece767f588ac99f458cb6cb367af947f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 518d4d673aed4390fc3b46bf190905da19566b31e86f2d20b82b7cc3efa1f4120244d69b6aaf2dafd2aecc6e90529df0362864b53511d218406d85ea33a8db98
|
|
7
|
+
data.tar.gz: 07621f0c66b4efb19536e34a08ca6a38ed3ae8bf2e760843363ff2ab9e0fcb8c5cf0b1b5626063856710378bfc09ca40f06f58d421e44a02fa432b547dc7cd7a
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.3
|
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
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
|
|
|
@@ -14,6 +14,9 @@ module RemoteResource
|
|
|
14
14
|
|
|
15
15
|
DEFAULT_EXTENSION = '.json'.freeze
|
|
16
16
|
|
|
17
|
+
DEFAULT_CONNECT_TIMEOUT = 30
|
|
18
|
+
DEFAULT_READ_TIMEOUT = 120
|
|
19
|
+
|
|
17
20
|
attr_reader :resource, :resource_klass, :http_action, :attributes
|
|
18
21
|
|
|
19
22
|
def initialize(resource, http_action, attributes = {}, connection_options = {})
|
|
@@ -41,7 +44,7 @@ module RemoteResource
|
|
|
41
44
|
def perform
|
|
42
45
|
SUPPORTED_HTTP_METHODS.include?(http_action) || raise(RemoteResource::HTTPMethodUnsupported, "Requested HTTP method=#{http_action.to_s} is NOT supported, the HTTP action MUST be a supported HTTP action=#{SUPPORTED_HTTP_METHODS.join(', ')}")
|
|
43
46
|
|
|
44
|
-
connection_response = connection.public_send(http_action, request_url, params: query, body: body, headers: headers)
|
|
47
|
+
connection_response = connection.public_send(http_action, request_url, params: query, body: body, headers: headers, **timeout_options)
|
|
45
48
|
response = RemoteResource::Response.new(connection_response, connection_options.merge(request: self, connection_request: connection_response.request))
|
|
46
49
|
|
|
47
50
|
if response.success? || response.unprocessable_entity?
|
|
@@ -76,7 +79,7 @@ module RemoteResource
|
|
|
76
79
|
def body
|
|
77
80
|
@body ||= begin
|
|
78
81
|
if [:put, :patch, :post].include?(http_action)
|
|
79
|
-
|
|
82
|
+
attributes.to_json
|
|
80
83
|
else
|
|
81
84
|
nil
|
|
82
85
|
end
|
|
@@ -84,12 +87,20 @@ module RemoteResource
|
|
|
84
87
|
end
|
|
85
88
|
|
|
86
89
|
def attributes
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
if connection_options[:json_spec] == :json_api
|
|
91
|
+
if @attributes
|
|
92
|
+
{ data: { id: @attributes[:id], type: resource_klass.name.demodulize, attributes: @attributes.except(:id) } }
|
|
93
|
+
else
|
|
94
|
+
{ data: {} }
|
|
95
|
+
end
|
|
91
96
|
else
|
|
92
|
-
|
|
97
|
+
root_element = connection_options[:root_element]
|
|
98
|
+
|
|
99
|
+
if root_element.present?
|
|
100
|
+
{ root_element => @attributes }
|
|
101
|
+
else
|
|
102
|
+
@attributes || {}
|
|
103
|
+
end
|
|
93
104
|
end
|
|
94
105
|
end
|
|
95
106
|
|
|
@@ -110,29 +121,58 @@ module RemoteResource
|
|
|
110
121
|
headers
|
|
111
122
|
end
|
|
112
123
|
|
|
124
|
+
def timeout_options
|
|
125
|
+
connecttimeout = connection_options[:connecttimeout].presence || DEFAULT_CONNECT_TIMEOUT
|
|
126
|
+
timeout = connection_options[:timeout].presence || DEFAULT_READ_TIMEOUT
|
|
127
|
+
|
|
128
|
+
{ connecttimeout: connecttimeout, timeout: timeout }
|
|
129
|
+
end
|
|
130
|
+
|
|
113
131
|
private
|
|
114
132
|
|
|
115
133
|
def raise_http_error(request, response)
|
|
134
|
+
# Special case if a request has a time out, as Typhoeus does not set a 408 response_code
|
|
135
|
+
raise RemoteResource::HTTPRequestTimeout.new(request, response) if response.timed_out?
|
|
136
|
+
|
|
116
137
|
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
|
|
138
|
+
when 301, 302, 303, 307 then
|
|
139
|
+
raise RemoteResource::HTTPRedirectionError.new(request, response)
|
|
140
|
+
when 400
|
|
141
|
+
raise RemoteResource::HTTPBadRequest.new(request, response)
|
|
142
|
+
when 401
|
|
143
|
+
raise RemoteResource::HTTPUnauthorized.new(request, response)
|
|
144
|
+
when 403
|
|
145
|
+
raise RemoteResource::HTTPForbidden.new(request, response)
|
|
146
|
+
when 404
|
|
147
|
+
raise RemoteResource::HTTPNotFound.new(request, response)
|
|
148
|
+
when 405
|
|
149
|
+
raise RemoteResource::HTTPMethodNotAllowed.new(request, response)
|
|
150
|
+
when 406
|
|
151
|
+
raise RemoteResource::HTTPNotAcceptable.new(request, response)
|
|
152
|
+
when 408
|
|
153
|
+
raise RemoteResource::HTTPRequestTimeout.new(request, response)
|
|
154
|
+
when 409
|
|
155
|
+
raise RemoteResource::HTTPConflict.new(request, response)
|
|
156
|
+
when 410
|
|
157
|
+
raise RemoteResource::HTTPGone.new(request, response)
|
|
158
|
+
when 418
|
|
159
|
+
raise RemoteResource::HTTPTeapot.new(request, response)
|
|
160
|
+
when 444
|
|
161
|
+
raise RemoteResource::HTTPNoResponse.new(request, response)
|
|
162
|
+
when 494
|
|
163
|
+
raise RemoteResource::HTTPRequestHeaderTooLarge.new(request, response)
|
|
164
|
+
when 495
|
|
165
|
+
raise RemoteResource::HTTPCertError.new(request, response)
|
|
166
|
+
when 496
|
|
167
|
+
raise RemoteResource::HTTPNoCert.new(request, response)
|
|
168
|
+
when 497
|
|
169
|
+
raise RemoteResource::HTTPToHTTPS.new(request, response)
|
|
170
|
+
when 499
|
|
171
|
+
raise RemoteResource::HTTPClientClosedRequest.new(request, response)
|
|
172
|
+
when 400..499
|
|
173
|
+
raise RemoteResource::HTTPClientError.new(request, response)
|
|
174
|
+
when 500..599
|
|
175
|
+
raise RemoteResource::HTTPServerError.new(request, response)
|
|
136
176
|
else
|
|
137
177
|
raise RemoteResource::HTTPError.new(request, response)
|
|
138
178
|
end
|
|
@@ -16,6 +16,10 @@ module RemoteResource
|
|
|
16
16
|
@connection_response.success?
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def timed_out?
|
|
20
|
+
@connection_response.timed_out?
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
def unprocessable_entity?
|
|
20
24
|
response_code == 422
|
|
21
25
|
end
|
|
@@ -44,19 +48,29 @@ module RemoteResource
|
|
|
44
48
|
|
|
45
49
|
def attributes
|
|
46
50
|
@attributes ||= begin
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
data
|
|
51
|
+
if @connection_options[:json_spec] == :json_api
|
|
52
|
+
data = parsed_body.fetch("data", {})
|
|
53
|
+
if data.is_a?(Array)
|
|
54
|
+
data.map { |row| row["attributes"].merge({ "id" => row["id"] }) }
|
|
55
|
+
elsif data.key?("attributes")
|
|
56
|
+
data["attributes"].merge({ "id" => data["id"] })
|
|
57
|
+
else
|
|
58
|
+
data
|
|
59
|
+
end
|
|
52
60
|
else
|
|
53
|
-
|
|
54
|
-
end
|
|
61
|
+
root_element = @connection_options[:root_element].to_s
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
if root_element.present?
|
|
64
|
+
data = parsed_body.try(:key?, root_element) && parsed_body[root_element]
|
|
65
|
+
else
|
|
66
|
+
data = parsed_body
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if data.is_a?(Array)
|
|
70
|
+
data
|
|
71
|
+
else
|
|
72
|
+
data.presence || {}
|
|
73
|
+
end
|
|
60
74
|
end
|
|
61
75
|
end
|
|
62
76
|
end
|
data/remote_resource.gemspec
CHANGED
|
@@ -6,8 +6,8 @@ require 'remote_resource/version'
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = 'ddy_remote_resource'
|
|
8
8
|
spec.version = RemoteResource::VERSION
|
|
9
|
-
spec.authors = ['Jan van der Pas']
|
|
10
|
-
spec.email = ['
|
|
9
|
+
spec.authors = ['Digidentity', 'Jan van der Pas']
|
|
10
|
+
spec.email = ['development@digidentity.com']
|
|
11
11
|
spec.summary = %q{RemoteResource, a gem to use resources with REST services.}
|
|
12
12
|
spec.description = %q{RemoteResource, a gem to use resources with REST services. A replacement for ActiveResource gem.}
|
|
13
13
|
spec.homepage = ''
|
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
spec.require_paths = ['lib']
|
|
20
20
|
|
|
21
|
-
spec.add_development_dependency 'bundler'
|
|
21
|
+
spec.add_development_dependency 'bundler'
|
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.4'
|
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.10'
|
|
@@ -27,11 +27,11 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
|
28
28
|
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.6'
|
|
29
29
|
|
|
30
|
-
spec.add_runtime_dependency 'activesupport', '>= 4.1', '<
|
|
31
|
-
spec.add_runtime_dependency 'activemodel', '>= 4.1', '<
|
|
30
|
+
spec.add_runtime_dependency 'activesupport', '>= 4.1', '< 7'
|
|
31
|
+
spec.add_runtime_dependency 'activemodel', '>= 4.1', '< 7'
|
|
32
32
|
spec.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.4'
|
|
33
33
|
spec.add_runtime_dependency 'mime-types', '~> 3.0'
|
|
34
|
-
spec.add_runtime_dependency 'ethon'
|
|
35
|
-
spec.add_runtime_dependency 'typhoeus', '
|
|
34
|
+
spec.add_runtime_dependency 'ethon'
|
|
35
|
+
spec.add_runtime_dependency 'typhoeus', '>= 0.7'
|
|
36
36
|
spec.add_runtime_dependency 'request_store', '~> 1.4.1'
|
|
37
37
|
end
|
|
@@ -44,7 +44,7 @@ RSpec.describe '.create' do
|
|
|
44
44
|
|
|
45
45
|
let!(:expected_request) do
|
|
46
46
|
mock_request = stub_request(:post, 'https://www.example.com/posts.json')
|
|
47
|
-
mock_request.with(query: nil, body:
|
|
47
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers)
|
|
48
48
|
mock_request.to_return(status: 201, body: JSON.generate(response_body))
|
|
49
49
|
mock_request
|
|
50
50
|
end
|
|
@@ -81,7 +81,7 @@ RSpec.describe '.create' do
|
|
|
81
81
|
|
|
82
82
|
let!(:expected_request) do
|
|
83
83
|
mock_request = stub_request(:post, 'https://www.example.com/posts.json')
|
|
84
|
-
mock_request.with(query: nil, body:
|
|
84
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
|
85
85
|
mock_request.to_return(status: 201, body: JSON.generate(response_body))
|
|
86
86
|
mock_request
|
|
87
87
|
end
|
|
@@ -114,7 +114,7 @@ RSpec.describe '.create' do
|
|
|
114
114
|
|
|
115
115
|
let!(:expected_request) do
|
|
116
116
|
mock_request = stub_request(:post, 'https://www.example.com/posts.json')
|
|
117
|
-
mock_request.with(query: nil, body:
|
|
117
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers)
|
|
118
118
|
mock_request.to_return(status: 422, body: JSON.generate(response_body))
|
|
119
119
|
mock_request
|
|
120
120
|
end
|
|
@@ -48,7 +48,7 @@ RSpec.describe '#save' do
|
|
|
48
48
|
describe 'default behaviour' do
|
|
49
49
|
let!(:expected_request) do
|
|
50
50
|
mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
|
|
51
|
-
mock_request.with(query: nil, body:
|
|
51
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers)
|
|
52
52
|
mock_request.to_return(status: 200, body: JSON.generate(response_body))
|
|
53
53
|
mock_request
|
|
54
54
|
end
|
|
@@ -77,7 +77,7 @@ RSpec.describe '#save' do
|
|
|
77
77
|
describe 'with connection_options[:headers]' do
|
|
78
78
|
let!(:expected_request) do
|
|
79
79
|
mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
|
|
80
|
-
mock_request.with(query: nil, body:
|
|
80
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
|
81
81
|
mock_request.to_return(status: 200, body: JSON.generate(response_body))
|
|
82
82
|
mock_request
|
|
83
83
|
end
|
|
@@ -111,7 +111,7 @@ RSpec.describe '#save' do
|
|
|
111
111
|
|
|
112
112
|
let!(:expected_request) do
|
|
113
113
|
mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
|
|
114
|
-
mock_request.with(query: nil, body:
|
|
114
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers)
|
|
115
115
|
mock_request.to_return(status: 422, body: JSON.generate(response_body))
|
|
116
116
|
mock_request
|
|
117
117
|
end
|
|
@@ -148,7 +148,7 @@ RSpec.describe '#save' do
|
|
|
148
148
|
describe 'with a 500 response' do
|
|
149
149
|
let!(:expected_request) do
|
|
150
150
|
mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
|
|
151
|
-
mock_request.with(query: nil, body:
|
|
151
|
+
mock_request.with(query: nil, body: expected_request_body.to_json, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
|
152
152
|
mock_request.to_return(status: 500)
|
|
153
153
|
mock_request
|
|
154
154
|
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[]',
|
|
@@ -166,7 +168,9 @@ RSpec.describe RemoteResource::Request do
|
|
|
166
168
|
let(:expected_connection_options) { request.connection_options }
|
|
167
169
|
|
|
168
170
|
it 'makes a GET request with the connection_options[:params] as query' do
|
|
169
|
-
expect(connection).to receive(:get).with(expected_request_url, params: expected_params,
|
|
171
|
+
expect(connection).to receive(:get).with(expected_request_url, params: expected_params,
|
|
172
|
+
body: expected_body, headers: expected_headers,
|
|
173
|
+
connecttimeout: 30, timeout: 120).and_call_original
|
|
170
174
|
request.perform
|
|
171
175
|
end
|
|
172
176
|
|
|
@@ -189,7 +193,9 @@ RSpec.describe RemoteResource::Request do
|
|
|
189
193
|
let(:expected_connection_options) { request.connection_options }
|
|
190
194
|
|
|
191
195
|
it 'makes a PUT request with the attributes as body' do
|
|
192
|
-
expect(connection).to receive(:put).with(expected_request_url, params: expected_params,
|
|
196
|
+
expect(connection).to receive(:put).with(expected_request_url, params: expected_params,
|
|
197
|
+
body: expected_body, headers: expected_headers,
|
|
198
|
+
connecttimeout: 30, timeout: 120).and_call_original
|
|
193
199
|
request.perform
|
|
194
200
|
end
|
|
195
201
|
|
|
@@ -212,7 +218,9 @@ RSpec.describe RemoteResource::Request do
|
|
|
212
218
|
let(:expected_connection_options) { request.connection_options }
|
|
213
219
|
|
|
214
220
|
it 'makes a PATCH request with the attributes as body' do
|
|
215
|
-
expect(connection).to receive(:patch).with(expected_request_url, params: expected_params,
|
|
221
|
+
expect(connection).to receive(:patch).with(expected_request_url, params: expected_params,
|
|
222
|
+
body: expected_body, headers: expected_headers,
|
|
223
|
+
connecttimeout: 30, timeout: 120).and_call_original
|
|
216
224
|
request.perform
|
|
217
225
|
end
|
|
218
226
|
|
|
@@ -235,7 +243,9 @@ RSpec.describe RemoteResource::Request do
|
|
|
235
243
|
let(:expected_connection_options) { request.connection_options }
|
|
236
244
|
|
|
237
245
|
it 'makes a POST request with the attributes as body' do
|
|
238
|
-
expect(connection).to receive(:post).with(expected_request_url, params: expected_params,
|
|
246
|
+
expect(connection).to receive(:post).with(expected_request_url, params: expected_params,
|
|
247
|
+
body: expected_body, headers: expected_headers,
|
|
248
|
+
connecttimeout: 30, timeout: 120).and_call_original
|
|
239
249
|
request.perform
|
|
240
250
|
end
|
|
241
251
|
|
|
@@ -258,7 +268,9 @@ RSpec.describe RemoteResource::Request do
|
|
|
258
268
|
let(:expected_connection_options) { request.connection_options }
|
|
259
269
|
|
|
260
270
|
it 'makes a DELETE request with the connection_options[:params] as query' do
|
|
261
|
-
expect(connection).to receive(:delete).with(expected_request_url, params: expected_params,
|
|
271
|
+
expect(connection).to receive(:delete).with(expected_request_url, params: expected_params,
|
|
272
|
+
body: expected_body, headers: expected_headers,
|
|
273
|
+
connecttimeout: 30, timeout: 120).and_call_original
|
|
262
274
|
request.perform
|
|
263
275
|
end
|
|
264
276
|
|
|
@@ -270,7 +282,7 @@ RSpec.describe RemoteResource::Request do
|
|
|
270
282
|
let(:expected_request_url) { '' }
|
|
271
283
|
|
|
272
284
|
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'
|
|
285
|
+
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
286
|
end
|
|
275
287
|
end
|
|
276
288
|
end
|
|
@@ -367,7 +379,7 @@ RSpec.describe RemoteResource::Request do
|
|
|
367
379
|
|
|
368
380
|
context 'when connection_options does NOT include collection_options' do
|
|
369
381
|
it 'raises error' do
|
|
370
|
-
expect{ request.request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
|
|
382
|
+
expect { request.request_url }.to raise_error(RemoteResource::CollectionOptionKeyError)
|
|
371
383
|
end
|
|
372
384
|
end
|
|
373
385
|
end
|
|
@@ -473,6 +485,30 @@ RSpec.describe RemoteResource::Request do
|
|
|
473
485
|
end
|
|
474
486
|
end
|
|
475
487
|
end
|
|
488
|
+
|
|
489
|
+
context 'when connection_options[:json_spec] == :json_api' do
|
|
490
|
+
let(:connection_options) do
|
|
491
|
+
{ json_spec: :json_api }
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
let(:attributes) do
|
|
495
|
+
{ id: 1, name: 'Mies', featured: true, labels: [1, '2', 'three'] }
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
it 'returns the given attributes wrapped in the json api spec' do
|
|
499
|
+
expect(request.attributes).to eql({ data: { id: 1, type: "RequestDummy", attributes: { name: 'Mies', featured: true, labels: [1, '2', 'three'] } } })
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
context 'and there are NO given attributes' do
|
|
503
|
+
let(:attributes) do
|
|
504
|
+
nil
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
it 'returns nil wrapped in the connection_options[:root_element]' do
|
|
508
|
+
expect(request.attributes).to eql({ data: {} })
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
end
|
|
476
512
|
end
|
|
477
513
|
|
|
478
514
|
describe '#headers' do
|
|
@@ -506,7 +542,7 @@ RSpec.describe RemoteResource::Request do
|
|
|
506
542
|
end
|
|
507
543
|
|
|
508
544
|
before { RemoteResource::Base.global_headers = { 'User-Agent' => 'From RemoteResource::Base.global_headers', 'X-Locale' => 'From RemoteResource::Base.global_headers' } }
|
|
509
|
-
after
|
|
545
|
+
after { RemoteResource::Base.global_headers = nil }
|
|
510
546
|
|
|
511
547
|
it 'returns the default headers while overwriting the headers according to the correct precedence' do
|
|
512
548
|
expect(request.headers).to eql expected_headers
|
|
@@ -560,9 +596,36 @@ RSpec.describe RemoteResource::Request do
|
|
|
560
596
|
end
|
|
561
597
|
end
|
|
562
598
|
|
|
599
|
+
describe '#timeout_options' do
|
|
600
|
+
it 'is not given by default' do
|
|
601
|
+
expect(request.connection_options).not_to include :connecttimeout, :timeout
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
context 'with custom timeouts' do
|
|
605
|
+
let(:connection_options) do
|
|
606
|
+
{ connecttimeout: 1, timeout: 2 }
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
it 'sets the timeouts from connection_options' do
|
|
610
|
+
aggregate_failures do
|
|
611
|
+
expect(request.connection_options[:connecttimeout]).to eq 1
|
|
612
|
+
expect(request.connection_options[:timeout]).to eq 2
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
|
|
563
618
|
describe '#raise_http_error' do
|
|
564
|
-
let(:connection_response) { instance_double(Typhoeus::Response, request: instance_double(Typhoeus::Request)) }
|
|
565
|
-
let(:response)
|
|
619
|
+
let(:connection_response) { instance_double(Typhoeus::Response, request: instance_double(Typhoeus::Request), timed_out?: false) }
|
|
620
|
+
let(:response) { RemoteResource::Response.new(connection_response, connection_options) }
|
|
621
|
+
|
|
622
|
+
context 'when the response has timed out' do
|
|
623
|
+
let(:connection_response) { instance_double(Typhoeus::Response, request: instance_double(Typhoeus::Request), timed_out?: true) }
|
|
624
|
+
|
|
625
|
+
it 'raises a RemoteResource::HTTPRequestTimeout' do
|
|
626
|
+
expect { request.send(:raise_http_error, request, response) }.to raise_error RemoteResource::HTTPRequestTimeout
|
|
627
|
+
end
|
|
628
|
+
end
|
|
566
629
|
|
|
567
630
|
context 'when the response code is 301, 302, 303 or 307' do
|
|
568
631
|
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,29 +1,30 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ddy_remote_resource
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
+
- Digidentity
|
|
7
8
|
- Jan van der Pas
|
|
8
9
|
autorequire:
|
|
9
10
|
bindir: bin
|
|
10
11
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
+
date: 2021-05-10 00:00:00.000000000 Z
|
|
12
13
|
dependencies:
|
|
13
14
|
- !ruby/object:Gem::Dependency
|
|
14
15
|
name: bundler
|
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
|
16
17
|
requirements:
|
|
17
|
-
- - "
|
|
18
|
+
- - ">="
|
|
18
19
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
20
|
+
version: '0'
|
|
20
21
|
type: :development
|
|
21
22
|
prerelease: false
|
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
24
|
requirements:
|
|
24
|
-
- - "
|
|
25
|
+
- - ">="
|
|
25
26
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
27
|
+
version: '0'
|
|
27
28
|
- !ruby/object:Gem::Dependency
|
|
28
29
|
name: rake
|
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -117,7 +118,7 @@ dependencies:
|
|
|
117
118
|
version: '4.1'
|
|
118
119
|
- - "<"
|
|
119
120
|
- !ruby/object:Gem::Version
|
|
120
|
-
version: '
|
|
121
|
+
version: '7'
|
|
121
122
|
type: :runtime
|
|
122
123
|
prerelease: false
|
|
123
124
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -127,7 +128,7 @@ dependencies:
|
|
|
127
128
|
version: '4.1'
|
|
128
129
|
- - "<"
|
|
129
130
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '
|
|
131
|
+
version: '7'
|
|
131
132
|
- !ruby/object:Gem::Dependency
|
|
132
133
|
name: activemodel
|
|
133
134
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -137,7 +138,7 @@ dependencies:
|
|
|
137
138
|
version: '4.1'
|
|
138
139
|
- - "<"
|
|
139
140
|
- !ruby/object:Gem::Version
|
|
140
|
-
version: '
|
|
141
|
+
version: '7'
|
|
141
142
|
type: :runtime
|
|
142
143
|
prerelease: false
|
|
143
144
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -147,7 +148,7 @@ dependencies:
|
|
|
147
148
|
version: '4.1'
|
|
148
149
|
- - "<"
|
|
149
150
|
- !ruby/object:Gem::Version
|
|
150
|
-
version: '
|
|
151
|
+
version: '7'
|
|
151
152
|
- !ruby/object:Gem::Dependency
|
|
152
153
|
name: virtus
|
|
153
154
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -186,42 +187,30 @@ dependencies:
|
|
|
186
187
|
name: ethon
|
|
187
188
|
requirement: !ruby/object:Gem::Requirement
|
|
188
189
|
requirements:
|
|
189
|
-
- - "~>"
|
|
190
|
-
- !ruby/object:Gem::Version
|
|
191
|
-
version: '0.7'
|
|
192
190
|
- - ">="
|
|
193
191
|
- !ruby/object:Gem::Version
|
|
194
|
-
version: 0
|
|
192
|
+
version: '0'
|
|
195
193
|
type: :runtime
|
|
196
194
|
prerelease: false
|
|
197
195
|
version_requirements: !ruby/object:Gem::Requirement
|
|
198
196
|
requirements:
|
|
199
|
-
- - "~>"
|
|
200
|
-
- !ruby/object:Gem::Version
|
|
201
|
-
version: '0.7'
|
|
202
197
|
- - ">="
|
|
203
198
|
- !ruby/object:Gem::Version
|
|
204
|
-
version: 0
|
|
199
|
+
version: '0'
|
|
205
200
|
- !ruby/object:Gem::Dependency
|
|
206
201
|
name: typhoeus
|
|
207
202
|
requirement: !ruby/object:Gem::Requirement
|
|
208
203
|
requirements:
|
|
209
|
-
- - "~>"
|
|
210
|
-
- !ruby/object:Gem::Version
|
|
211
|
-
version: '0.7'
|
|
212
204
|
- - ">="
|
|
213
205
|
- !ruby/object:Gem::Version
|
|
214
|
-
version: 0.7
|
|
206
|
+
version: '0.7'
|
|
215
207
|
type: :runtime
|
|
216
208
|
prerelease: false
|
|
217
209
|
version_requirements: !ruby/object:Gem::Requirement
|
|
218
210
|
requirements:
|
|
219
|
-
- - "~>"
|
|
220
|
-
- !ruby/object:Gem::Version
|
|
221
|
-
version: '0.7'
|
|
222
211
|
- - ">="
|
|
223
212
|
- !ruby/object:Gem::Version
|
|
224
|
-
version: 0.7
|
|
213
|
+
version: '0.7'
|
|
225
214
|
- !ruby/object:Gem::Dependency
|
|
226
215
|
name: request_store
|
|
227
216
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -239,7 +228,7 @@ dependencies:
|
|
|
239
228
|
description: RemoteResource, a gem to use resources with REST services. A replacement
|
|
240
229
|
for ActiveResource gem.
|
|
241
230
|
email:
|
|
242
|
-
-
|
|
231
|
+
- development@digidentity.com
|
|
243
232
|
executables: []
|
|
244
233
|
extensions: []
|
|
245
234
|
extra_rdoc_files: []
|
|
@@ -319,8 +308,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
319
308
|
- !ruby/object:Gem::Version
|
|
320
309
|
version: '0'
|
|
321
310
|
requirements: []
|
|
322
|
-
|
|
323
|
-
rubygems_version: 2.7.7
|
|
311
|
+
rubygems_version: 3.2.15
|
|
324
312
|
signing_key:
|
|
325
313
|
specification_version: 4
|
|
326
314
|
summary: RemoteResource, a gem to use resources with REST services.
|