ddy_remote_resource 1.0.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|