ddy_remote_resource 1.0.4 → 1.2.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/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/lib/remote_resource.rb +1 -0
- data/lib/remote_resource/base.rb +6 -5
- data/lib/remote_resource/connection_options.rb +1 -1
- data/lib/remote_resource/request.rb +67 -27
- data/lib/remote_resource/response.rb +25 -11
- data/lib/remote_resource/version.rb +1 -1
- data/remote_resource.gemspec +5 -4
- data/spec/integration/create_spec.rb +3 -3
- data/spec/integration/save_spec.rb +4 -4
- data/spec/lib/remote_resource/base_spec.rb +1 -1
- data/spec/lib/remote_resource/connection_options_spec.rb +5 -4
- data/spec/lib/remote_resource/request_spec.rb +79 -16
- data/spec/lib/remote_resource/response_spec.rb +33 -3
- data/spec/lib/remote_resource/version_spec.rb +1 -3
- metadata +23 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d0032d56e8df7f6e90e146abb65b29a41a59a63e39747c6b0b7585c02f577069
|
4
|
+
data.tar.gz: 4454b9226626e5a2028dc871c83d15347da8a373d104e641810c3f002e8e94c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 327330942d08e782894d10b46be1c6a6fc560f4cab2a4f7bb77a2b2958853ad929a024ccc00c560a3672e48c55a5844e9064e9c7fc00ae9839228d904038f2b6
|
7
|
+
data.tar.gz: f6d6b6c025c695cd68f4697b9a001046d54a29b32f51aabbec187ff9359bf32da6db83510cc5a3a251729159100e06b11054986a009d55386ece26e5f372ed8b
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3
|
1
|
+
2.5.3
|
data/.travis.yml
CHANGED
data/lib/remote_resource.rb
CHANGED
data/lib/remote_resource/base.rb
CHANGED
@@ -23,16 +23,17 @@ module RemoteResource
|
|
23
23
|
attr_writer :destroyed, :persisted, :success
|
24
24
|
|
25
25
|
class_attribute :root_element, instance_accessor: false
|
26
|
+
class_attribute :json_spec, instance_accessor: false
|
26
27
|
|
27
28
|
attribute :id
|
28
29
|
end
|
29
30
|
|
30
31
|
def self.global_headers=(headers)
|
31
|
-
|
32
|
+
RequestStore.store[:global_headers] = headers
|
32
33
|
end
|
33
34
|
|
34
35
|
def self.global_headers
|
35
|
-
|
36
|
+
RequestStore.store[:global_headers] ||= {}
|
36
37
|
end
|
37
38
|
|
38
39
|
module ClassMethods
|
@@ -42,15 +43,15 @@ module RemoteResource
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def threaded_connection_options
|
45
|
-
|
46
|
+
RequestStore.store[threaded_connection_options_thread_name] ||= {}
|
46
47
|
end
|
47
48
|
|
48
49
|
def with_connection_options(connection_options = {})
|
49
50
|
begin
|
50
|
-
|
51
|
+
RequestStore.store[threaded_connection_options_thread_name] = threaded_connection_options.merge(connection_options)
|
51
52
|
yield
|
52
53
|
ensure
|
53
|
-
|
54
|
+
RequestStore.store[threaded_connection_options_thread_name] = nil
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -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
|
|
@@ -106,33 +117,62 @@ module RemoteResource
|
|
106
117
|
def conditional_headers
|
107
118
|
headers = {}
|
108
119
|
headers = headers.merge(DEFAULT_CONTENT_TYPE) if body.present?
|
109
|
-
headers = headers.merge({ 'X-Request-Id' =>
|
120
|
+
headers = headers.merge({ 'X-Request-Id' => RequestStore.store[:request_id] }) if RequestStore.store[:request_id].present?
|
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 = ''
|
@@ -27,10 +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
34
|
spec.add_runtime_dependency 'ethon', '~> 0.7', '>= 0.7.1'
|
35
35
|
spec.add_runtime_dependency 'typhoeus', '~> 0.7', '>= 0.7.0'
|
36
|
+
spec.add_runtime_dependency 'request_store', '~> 1.4.1'
|
36
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
|
@@ -81,7 +81,7 @@ RSpec.describe RemoteResource::Base do
|
|
81
81
|
end
|
82
82
|
|
83
83
|
it 'sets the name of Thread variable with the implemented class' do
|
84
|
-
expect(dummy_class.threaded_connection_options).to eql
|
84
|
+
expect(dummy_class.threaded_connection_options).to eql RequestStore.store['remote_resource.dummy.threaded_connection_options']
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -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
|
@@ -540,13 +576,13 @@ RSpec.describe RemoteResource::Request do
|
|
540
576
|
end
|
541
577
|
end
|
542
578
|
|
543
|
-
context 'when
|
579
|
+
context 'when RequestStore.store[:request_id] is present' do
|
544
580
|
before do
|
545
|
-
|
581
|
+
RequestStore.store[:request_id] = 'CASCADING-REQUEST-ID'
|
546
582
|
end
|
547
583
|
|
548
584
|
after do
|
549
|
-
|
585
|
+
RequestStore.store[:request_id] = nil
|
550
586
|
end
|
551
587
|
|
552
588
|
let(:expected_headers) do
|
@@ -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,14 +1,15 @@
|
|
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.2.0
|
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-01-08 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -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
|
@@ -222,10 +223,24 @@ dependencies:
|
|
222
223
|
- - ">="
|
223
224
|
- !ruby/object:Gem::Version
|
224
225
|
version: 0.7.0
|
226
|
+
- !ruby/object:Gem::Dependency
|
227
|
+
name: request_store
|
228
|
+
requirement: !ruby/object:Gem::Requirement
|
229
|
+
requirements:
|
230
|
+
- - "~>"
|
231
|
+
- !ruby/object:Gem::Version
|
232
|
+
version: 1.4.1
|
233
|
+
type: :runtime
|
234
|
+
prerelease: false
|
235
|
+
version_requirements: !ruby/object:Gem::Requirement
|
236
|
+
requirements:
|
237
|
+
- - "~>"
|
238
|
+
- !ruby/object:Gem::Version
|
239
|
+
version: 1.4.1
|
225
240
|
description: RemoteResource, a gem to use resources with REST services. A replacement
|
226
241
|
for ActiveResource gem.
|
227
242
|
email:
|
228
|
-
-
|
243
|
+
- development@digidentity.com
|
229
244
|
executables: []
|
230
245
|
extensions: []
|
231
246
|
extra_rdoc_files: []
|
@@ -306,7 +321,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
306
321
|
version: '0'
|
307
322
|
requirements: []
|
308
323
|
rubyforge_project:
|
309
|
-
rubygems_version: 2.
|
324
|
+
rubygems_version: 2.7.6
|
310
325
|
signing_key:
|
311
326
|
specification_version: 4
|
312
327
|
summary: RemoteResource, a gem to use resources with REST services.
|