restful_resource 2.6.1 → 2.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 015747ee95ac4e52617a009da36dcccb671aa6f8437662287f9dadf951f2049e
4
- data.tar.gz: c27835d8a584d1d5c228725892ceca06cb215cbdee088d7c2b6884228371aab1
3
+ metadata.gz: '081a984e1de78fc016fefc2780fcb3704500150aadbd9522ed7ef2f853974280'
4
+ data.tar.gz: b6c1c0c81446ad5bd91425331a8da03e41472dde92f5b212cc77fb135b259fac
5
5
  SHA512:
6
- metadata.gz: 9d987975b117009d80e0179663ab643a24d055220b01f149be44d12024968732166ec9a589d9517f27150630a8794b0e2557b8fe72ff332be8a3472dab74deb6
7
- data.tar.gz: 1cebc647b6ddfca2d0fee0ab9bb9d32ef1820f3d06d613a7417b38f9c28617569bfcfe3f6dac7fe71eff47c8c8b7041876cbc54a90fb6d78438e39ae720cac13
6
+ metadata.gz: ea91622af6f36d6a3263ffe856bd86eb625e67114391409dce009622091924cb4f6b7e994925f2f76aa994184b8043a031c4e40ea65abd0b8c274cf6f2569e06
7
+ data.tar.gz: 1dc365a6041eeb909e6f3c70450682a90ad1203aaecd26a6fd48335330ab6ec8608a9c10bf034100c235d1ed3a9e2fda82787a48773d45251eca582cdf6f6d84
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ tmp
17
17
  .idea
18
18
  *.swp
19
19
  *.swo
20
+ /tags
@@ -1,7 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ 2.10.0
4
+ ---
5
+
6
+ - Support Faraday v1 (#85)
7
+
8
+ 2.9.0
9
+ ---
10
+
11
+ - Add support for DELETE in RestfulResource::RailsValidations (#73)
12
+
13
+ 2.8.1
14
+ ---
15
+
16
+ - Looser Faraday requirement >= 0.15, < 1.1
17
+
18
+ 2.8.0
19
+ ---
20
+
21
+ - Make params hash in methods consistent, and always optional (#61)
22
+
23
+ 2.7.0
24
+ ---
25
+
26
+ - Add `X-Client-Start` header on request containing milliseconds since unix epoch
27
+
3
28
  2.6.1
4
29
  ---
30
+
5
31
  - Support only `faraday-0.15.x`
6
32
  - `0.16.x` breaks `faraday-http-cache`
7
33
 
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'pry'
@@ -1,100 +1,103 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- restful_resource (2.6.1)
5
- activesupport
6
- faraday (~> 0.15.0)
7
- faraday-cdn-metrics
4
+ restful_resource (2.10.1)
5
+ activesupport (~> 6.0)
6
+ faraday (~> 1.0)
7
+ faraday-cdn-metrics (~> 0.2)
8
8
  faraday-encoding
9
- faraday-http-cache
10
- faraday_middleware
9
+ faraday-http-cache (~> 2.2)
10
+ faraday_middleware (~> 1.0)
11
11
  link_header
12
- rack
13
- typhoeus
12
+ rack (~> 2.2)
13
+ typhoeus (~> 1.4)
14
14
 
15
15
  GEM
16
16
  remote: https://rubygems.org/
17
17
  specs:
18
- activesupport (6.0.0)
18
+ activesupport (6.0.3.3)
19
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
20
20
  i18n (>= 0.7, < 2)
21
21
  minitest (~> 5.1)
22
22
  tzinfo (~> 1.1)
23
- zeitwerk (~> 2.1, >= 2.1.8)
23
+ zeitwerk (~> 2.2, >= 2.2.2)
24
24
  ast (2.4.0)
25
- carwow_rubocop (3.0.3)
26
- rubocop (>= 0.68)
25
+ carwow_rubocop (3.3.0)
26
+ rubocop (>= 0.78)
27
27
  rubocop-performance
28
28
  rubocop-rspec
29
29
  coderay (1.1.2)
30
- concurrent-ruby (1.1.5)
30
+ concurrent-ruby (1.1.7)
31
31
  diff-lcs (1.3)
32
32
  ethon (0.12.0)
33
33
  ffi (>= 1.3.0)
34
- faraday (0.15.4)
34
+ faraday (1.0.1)
35
35
  multipart-post (>= 1.2, < 3)
36
- faraday-cdn-metrics (0.1.0)
37
- faraday (~> 0.11)
36
+ faraday-cdn-metrics (0.2.0)
37
+ faraday (~> 1)
38
38
  faraday-encoding (0.0.5)
39
39
  faraday
40
- faraday-http-cache (2.0.0)
41
- faraday (~> 0.8)
42
- faraday_middleware (0.13.1)
43
- faraday (>= 0.7.4, < 1.0)
44
- ffi (1.11.1)
45
- i18n (1.6.0)
40
+ faraday-http-cache (2.2.0)
41
+ faraday (>= 0.8)
42
+ faraday_middleware (1.0.0)
43
+ faraday (~> 1.0)
44
+ ffi (1.13.1)
45
+ i18n (1.8.5)
46
46
  concurrent-ruby (~> 1.0)
47
- jaro_winkler (1.5.3)
48
47
  link_header (0.0.8)
49
- method_source (0.9.2)
50
- minitest (5.12.2)
48
+ method_source (1.0.0)
49
+ minitest (5.14.2)
51
50
  multipart-post (2.1.1)
52
- parallel (1.17.0)
53
- parser (2.6.3.0)
51
+ parallel (1.19.1)
52
+ parser (2.7.1.2)
54
53
  ast (~> 2.4.0)
55
- pry (0.12.2)
56
- coderay (~> 1.1.0)
57
- method_source (~> 0.9.0)
58
- rack (2.0.7)
54
+ pry (0.13.1)
55
+ coderay (~> 1.1)
56
+ method_source (~> 1.0)
57
+ rack (2.2.3)
59
58
  rainbow (3.0.0)
60
- rake (12.3.3)
61
- rspec (3.8.0)
62
- rspec-core (~> 3.8.0)
63
- rspec-expectations (~> 3.8.0)
64
- rspec-mocks (~> 3.8.0)
65
- rspec-core (3.8.2)
66
- rspec-support (~> 3.8.0)
67
- rspec-expectations (3.8.4)
59
+ rake (13.0.1)
60
+ rexml (3.2.4)
61
+ rspec (3.9.0)
62
+ rspec-core (~> 3.9.0)
63
+ rspec-expectations (~> 3.9.0)
64
+ rspec-mocks (~> 3.9.0)
65
+ rspec-core (3.9.0)
66
+ rspec-support (~> 3.9.0)
67
+ rspec-expectations (3.9.0)
68
68
  diff-lcs (>= 1.2.0, < 2.0)
69
- rspec-support (~> 3.8.0)
69
+ rspec-support (~> 3.9.0)
70
70
  rspec-its (1.3.0)
71
71
  rspec-core (>= 3.0.0)
72
72
  rspec-expectations (>= 3.0.0)
73
- rspec-mocks (3.8.1)
73
+ rspec-mocks (3.9.0)
74
74
  diff-lcs (>= 1.2.0, < 2.0)
75
- rspec-support (~> 3.8.0)
76
- rspec-support (3.8.2)
75
+ rspec-support (~> 3.9.0)
76
+ rspec-support (3.9.0)
77
77
  rspec_junit_formatter (0.4.1)
78
78
  rspec-core (>= 2, < 4, != 2.12.0)
79
- rubocop (0.73.0)
80
- jaro_winkler (~> 1.5.1)
79
+ rubocop (0.84.0)
81
80
  parallel (~> 1.10)
82
- parser (>= 2.6)
81
+ parser (>= 2.7.0.1)
83
82
  rainbow (>= 2.2.2, < 4.0)
83
+ rexml
84
+ rubocop-ast (>= 0.0.3)
84
85
  ruby-progressbar (~> 1.7)
85
- unicode-display_width (>= 1.4.0, < 1.7)
86
- rubocop-performance (1.4.1)
86
+ unicode-display_width (>= 1.4.0, < 2.0)
87
+ rubocop-ast (0.0.3)
88
+ parser (>= 2.7.0.1)
89
+ rubocop-performance (1.6.0)
87
90
  rubocop (>= 0.71.0)
88
- rubocop-rspec (1.34.1)
89
- rubocop (>= 0.60.0)
91
+ rubocop-rspec (1.39.0)
92
+ rubocop (>= 0.68.1)
90
93
  ruby-progressbar (1.10.1)
91
94
  thread_safe (0.3.6)
92
- typhoeus (1.3.1)
95
+ typhoeus (1.4.0)
93
96
  ethon (>= 0.9.0)
94
- tzinfo (1.2.5)
97
+ tzinfo (1.2.7)
95
98
  thread_safe (~> 0.1)
96
- unicode-display_width (1.6.0)
97
- zeitwerk (2.1.10)
99
+ unicode-display_width (1.7.0)
100
+ zeitwerk (2.4.0)
98
101
 
99
102
  PLATFORMS
100
103
  ruby
@@ -110,4 +113,4 @@ DEPENDENCIES
110
113
  rspec_junit_formatter
111
114
 
112
115
  BUNDLED WITH
113
- 2.0.2
116
+ 2.1.4
@@ -33,14 +33,14 @@ module RestfulResource
33
33
  @resource_path = url
34
34
  end
35
35
 
36
- def self.find(id, params = {})
36
+ def self.find(id, **params)
37
37
  params_without_options, options = format_params(params)
38
38
 
39
- response = http.get(member_url(id, params_without_options), **options)
39
+ response = http.get(member_url(id, **params_without_options), **options)
40
40
  new(parse_json(response.body))
41
41
  end
42
42
 
43
- def self.where(params = {})
43
+ def self.where(**params)
44
44
  params_without_options, options = format_params(params)
45
45
 
46
46
  url = collection_url(params_without_options)
@@ -48,7 +48,7 @@ module RestfulResource
48
48
  paginate_response(response)
49
49
  end
50
50
 
51
- def self.get(params = {})
51
+ def self.get(**params)
52
52
  params_without_options, options = format_params(params)
53
53
 
54
54
  response = http.get(collection_url(params_without_options), **options)
@@ -57,15 +57,15 @@ module RestfulResource
57
57
 
58
58
  def self.delete(id, **params)
59
59
  params_without_options, options = format_params(params)
60
- response = http.delete(member_url(id, params_without_options), **options)
61
- RestfulResource::OpenObject.new(parse_json(response.body))
60
+ response = http.delete(member_url(id, **params_without_options), **options)
61
+ new(parse_json(response.body))
62
62
  end
63
63
 
64
64
  def self.patch(id, data: {}, headers: {}, **params)
65
65
  params_without_options, options = format_params(params)
66
66
  options.delete(:headers)
67
67
 
68
- url = member_url(id, params_without_options)
68
+ url = member_url(id, **params_without_options)
69
69
 
70
70
  response = http.patch(url, data: data, headers: headers, **options)
71
71
  new(parse_json(response.body))
@@ -75,7 +75,7 @@ module RestfulResource
75
75
  params_without_options, options = format_params(params)
76
76
  options.delete(:headers)
77
77
 
78
- url = member_url(id, params_without_options)
78
+ url = member_url(id, **params_without_options)
79
79
 
80
80
  response = http.put(url, data: data, headers: headers, **options)
81
81
  new(parse_json(response.body))
@@ -92,7 +92,7 @@ module RestfulResource
92
92
  new(parse_json(response.body))
93
93
  end
94
94
 
95
- def self.all(params = {})
95
+ def self.all(**params)
96
96
  where(params)
97
97
  end
98
98
 
@@ -133,14 +133,14 @@ module RestfulResource
133
133
  result
134
134
  end
135
135
 
136
- def self.collection_url(params)
136
+ def self.collection_url(**params)
137
137
  url = merge_url_paths(base_url, @resource_path, @action_prefix)
138
138
  replace_parameters(url, params)
139
139
  end
140
140
 
141
141
  private
142
142
 
143
- def self.format_params(params = {})
143
+ def self.format_params(**params)
144
144
  headers = params.delete(:headers) || {}
145
145
 
146
146
  headers[:cache_control] = 'no-cache' if params.delete(:no_cache)
@@ -154,11 +154,11 @@ module RestfulResource
154
154
  uri.merge(paths.compact.join('/')).to_s
155
155
  end
156
156
 
157
- def self.member_url(id, params)
157
+ def self.member_url(id, **params)
158
158
  raise ResourceIdMissingError if id.blank?
159
159
 
160
160
  url = merge_url_paths(base_url, @resource_path, CGI.escape(id.to_s), @action_prefix)
161
- replace_parameters(url, params)
161
+ replace_parameters(url, **params)
162
162
  end
163
163
 
164
164
  def self.new_collection(json)
@@ -173,7 +173,7 @@ module RestfulResource
173
173
  ActiveSupport::JSON.decode(json)
174
174
  end
175
175
 
176
- def self.replace_parameters(url, params)
176
+ def self.replace_parameters(url, **params)
177
177
  missing_params = []
178
178
  params = params.with_indifferent_access
179
179
 
@@ -252,7 +252,7 @@ module RestfulResource
252
252
  req.body = request.body unless request.body.nil?
253
253
  req.url request.url
254
254
 
255
- req.headers = req.headers.merge(request.headers)
255
+ req.headers = req.headers.merge(request.headers).merge(x_client_start: time_current_ms)
256
256
  req.headers = req.headers.merge(x_client_timeout: req.options[:timeout]) if req.options[:timeout]
257
257
  end
258
258
 
@@ -267,7 +267,10 @@ module RestfulResource
267
267
 
268
268
  handle_error(request, response)
269
269
  rescue Faraday::ServerError => e
270
- handle_error(request, e.response)
270
+ response = e.response
271
+ raise ClientError, request unless response
272
+
273
+ handle_error(request, response)
271
274
  end
272
275
 
273
276
  def handle_error(request, response)
@@ -282,5 +285,9 @@ module RestfulResource
282
285
  else raise HttpClient::OtherHttpError.new(request, response)
283
286
  end
284
287
  end
288
+
289
+ def time_current_ms
290
+ (Time.current.to_f * 1_000.0).to_i
291
+ end
285
292
  end
286
293
  end
@@ -17,13 +17,16 @@ module RestfulResource
17
17
  with_validations { super }
18
18
  end
19
19
 
20
+ def delete(*)
21
+ with_validations { super }
22
+ end
23
+
20
24
  private
21
25
 
22
26
  def with_validations(id = nil, data: {})
23
27
  yield
24
28
  rescue HttpClient::UnprocessableEntity => e
25
29
  errors = parse_json(e.response.body)
26
- result = nil
27
30
  result = if errors.is_a?(Hash) && errors.key?('errors')
28
31
  data.merge(errors)
29
32
  else
@@ -1,3 +1,3 @@
1
1
  module RestfulResource
2
- VERSION = '2.6.1'.freeze
2
+ VERSION = '2.10.1'.freeze
3
3
  end
@@ -20,18 +20,19 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency 'bundler'
22
22
  spec.add_development_dependency 'carwow_rubocop'
23
+ spec.add_development_dependency 'pry'
23
24
  spec.add_development_dependency 'rake'
24
25
  spec.add_development_dependency 'rspec'
25
- spec.add_development_dependency 'rspec_junit_formatter'
26
26
  spec.add_development_dependency 'rspec-its'
27
+ spec.add_development_dependency 'rspec_junit_formatter'
27
28
 
28
- spec.add_dependency 'activesupport'
29
- spec.add_dependency 'faraday', '~> 0.15.0'
30
- spec.add_dependency 'faraday-cdn-metrics'
29
+ spec.add_dependency 'activesupport', '~> 6.0'
30
+ spec.add_dependency 'faraday', '~> 1.0'
31
+ spec.add_dependency 'faraday-cdn-metrics', '~> 0.2'
31
32
  spec.add_dependency 'faraday-encoding'
32
- spec.add_dependency 'faraday-http-cache'
33
- spec.add_dependency 'faraday_middleware'
33
+ spec.add_dependency 'faraday-http-cache', '~> 2.2'
34
+ spec.add_dependency 'faraday_middleware', '~> 1.0'
34
35
  spec.add_dependency 'link_header'
35
- spec.add_dependency 'rack'
36
- spec.add_dependency 'typhoeus'
36
+ spec.add_dependency 'rack', '~> 2.2'
37
+ spec.add_dependency 'typhoeus', '~> 1.4'
37
38
  end
@@ -19,7 +19,7 @@ describe RestfulResource::HttpClient do
19
19
 
20
20
  describe 'Builder configuration' do
21
21
  it 'uses the typhoeus adapter' do
22
- expect(middleware).to include Faraday::Adapter::Typhoeus
22
+ expect(connection.adapter).to eq Faraday::Adapter::Typhoeus
23
23
  end
24
24
 
25
25
  it 'url_encodes requests' do
@@ -81,13 +81,13 @@ describe RestfulResource::HttpClient do
81
81
  described_class.new(instrumentation: { app_name: 'rails', api_name: 'api', metric_class: FakeMetrics })
82
82
 
83
83
  expect(RestfulResource::Instrumentation).to have_received(:new)
84
- .with(app_name: 'rails',
85
- api_name: 'api',
86
- request_instrument_name: 'http.api',
87
- cache_instrument_name: 'http_cache.api',
88
- server_cache_instrument_name: 'cdn_metrics.api',
89
- metric_class: FakeMetrics
90
- )
84
+ .with(app_name: 'rails',
85
+ api_name: 'api',
86
+ request_instrument_name: 'http.api',
87
+ cache_instrument_name: 'http_cache.api',
88
+ server_cache_instrument_name: 'cdn_metrics.api',
89
+ metric_class: FakeMetrics
90
+ )
91
91
  end
92
92
 
93
93
  it 'subscribes to the notifications' do
@@ -16,175 +16,97 @@ RSpec.describe RestfulResource::HttpClient do
16
16
  end
17
17
 
18
18
  describe 'Basic HTTP' do
19
- it 'executes get' do
20
- connection = faraday_connection do |stubs|
21
- stubs.get('http://httpbin.org/get') { |_env| [200, {}, nil] }
22
- end
23
-
24
- response = http_client(connection).get('http://httpbin.org/get')
25
- expect(response.status).to eq 200
26
- end
27
-
28
- it 'executes patch' do
29
- connection = faraday_connection do |stubs|
30
- # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
31
- stubs.patch('http://httpbin.org/patch', 'name=Alfred') { |_env| [200, {}, nil] }
32
- end
33
-
34
- response = http_client(connection).patch('http://httpbin.org/patch', data: { name: 'Alfred' })
35
- expect(response.status).to eq 200
36
- end
37
-
38
- it 'executes put' do
39
- connection = faraday_connection do |stubs|
40
- # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
41
- stubs.put('http://httpbin.org/put', 'name=Alfred') { |_env| [200, {}, nil] }
42
- end
43
-
44
- response = http_client(connection).put('http://httpbin.org/put', data: { name: 'Alfred' })
45
- expect(response.status).to eq 200
46
- end
47
-
48
- it 'executes post' do
49
- connection = faraday_connection do |stubs|
50
- # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
51
- stubs.post('http://httpbin.org/post', 'name=Alfred') { |_env| [200, {}, %("name": "Alfred")] }
52
- end
53
-
54
- response = http_client(connection).post('http://httpbin.org/post', data: { name: 'Alfred' })
55
-
56
- expect(response.body).to include 'name": "Alfred'
57
- expect(response.status).to eq 200
58
- end
59
-
60
- it 'executes delete' do
61
- connection = faraday_connection do |stubs|
62
- stubs.delete('http://httpbin.org/delete') { |_env| [200, {}, nil] }
63
- end
19
+ shared_examples 'error codes throw exception' do |verb, status, exception_class|
20
+ it "should raise an error #{status}" do
21
+ url = "http://httpbin.org/status/#{status}"
64
22
 
65
- response = http_client(connection).delete('http://httpbin.org/delete')
66
-
67
- expect(response.status).to eq 200
68
- end
69
-
70
- it 'patch should raise error 409' do
71
- connection = faraday_connection do |stubs|
72
- stubs.patch('http://httpbin.org/status/409') { |_env| [409, {}, nil] }
73
- end
74
-
75
- expect { http_client(connection).patch('http://httpbin.org/status/409') }.to raise_error(RestfulResource::HttpClient::Conflict)
76
- end
23
+ connection = faraday_connection do |stubs|
24
+ stubs.send(verb, url) { [status, {}, nil] }
25
+ end
77
26
 
78
- it 'patch should raise error 422' do
79
- connection = faraday_connection do |stubs|
80
- stubs.patch('http://httpbin.org/status/422') { |_env| [422, {}, nil] }
27
+ expect { http_client(connection).send(verb, url) }.to raise_error(exception_class)
81
28
  end
82
-
83
- expect { http_client(connection).patch('http://httpbin.org/status/422') }.to raise_error(RestfulResource::HttpClient::UnprocessableEntity)
84
29
  end
85
30
 
86
- it 'put should raise error 409' do
87
- connection = faraday_connection do |stubs|
88
- stubs.put('http://httpbin.org/status/409') { |_env| [409, {}, nil] }
89
- end
31
+ shared_examples 'raise an exception on error responses' do |verb|
32
+ include_examples 'error codes throw exception', verb, 409, RestfulResource::HttpClient::Conflict
33
+ include_examples 'error codes throw exception', verb, 404, RestfulResource::HttpClient::ResourceNotFound
34
+ include_examples 'error codes throw exception', verb, 422, RestfulResource::HttpClient::UnprocessableEntity
35
+ include_examples 'error codes throw exception', verb, 429, RestfulResource::HttpClient::TooManyRequests
36
+ include_examples 'error codes throw exception', verb, 502, RestfulResource::HttpClient::BadGateway
37
+ include_examples 'error codes throw exception', verb, 503, RestfulResource::HttpClient::ServiceUnavailable
38
+ include_examples 'error codes throw exception', verb, 504, RestfulResource::HttpClient::GatewayTimeout
90
39
 
91
- expect { http_client(connection).put('http://httpbin.org/status/409') }.to raise_error(RestfulResource::HttpClient::Conflict)
40
+ include_examples 'error codes throw exception', verb, 418, RestfulResource::HttpClient::OtherHttpError
92
41
  end
93
42
 
94
- it 'put should raise error 422' do
95
- connection = faraday_connection do |stubs|
96
- stubs.put('http://httpbin.org/status/422') { |_env| [422, {}, nil] }
97
- end
43
+ context 'GET' do
44
+ include_examples 'raise an exception on error responses', :get
98
45
 
99
- expect { http_client(connection).put('http://httpbin.org/status/422') }.to raise_error(RestfulResource::HttpClient::UnprocessableEntity)
100
- end
46
+ it 'executes get' do
47
+ connection = faraday_connection do |stubs|
48
+ stubs.get('http://httpbin.org/get') { |_env| [200, {}, nil] }
49
+ end
101
50
 
102
- it 'post should raise error 422' do
103
- connection = faraday_connection do |stubs|
104
- stubs.post('http://httpbin.org/status/422') { |_env| [422, {}, nil] }
51
+ response = http_client(connection).get('http://httpbin.org/get')
52
+ expect(response.status).to eq 200
105
53
  end
106
-
107
- expect { http_client(connection).post('http://httpbin.org/status/422') }.to raise_error(RestfulResource::HttpClient::UnprocessableEntity)
108
54
  end
109
55
 
110
- it 'post should raise error 429' do
111
- connection = faraday_connection do |stubs|
112
- stubs.post('http://httpbin.org/status/429') { |_env| [429, {}, nil] }
113
- end
56
+ context 'PATCH' do
57
+ include_examples 'raise an exception on error responses', :patch
114
58
 
115
- expect { http_client(connection).post('http://httpbin.org/status/429') }.to raise_error(RestfulResource::HttpClient::TooManyRequests)
116
- end
59
+ it 'executes patch' do
60
+ connection = faraday_connection do |stubs|
61
+ # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
62
+ stubs.patch('http://httpbin.org/patch', 'name=Alfred') { |_env| [200, {}, nil] }
63
+ end
117
64
 
118
- it 'patch should raise error 502' do
119
- connection = faraday_connection do |stubs|
120
- stubs.patch('http://httpbin.org/status/502') { |_env| [502, {}, nil] }
65
+ response = http_client(connection).patch('http://httpbin.org/patch', data: { name: 'Alfred' })
66
+ expect(response.status).to eq 200
121
67
  end
122
-
123
- expect { http_client(connection).patch('http://httpbin.org/status/502') }.to raise_error(RestfulResource::HttpClient::BadGateway)
124
68
  end
125
69
 
126
- it 'put should raise error 502' do
127
- connection = faraday_connection do |stubs|
128
- stubs.put('http://httpbin.org/status/502') { |_env| [502, {}, nil] }
129
- end
130
-
131
- expect { http_client(connection).put('http://httpbin.org/status/502') }.to raise_error(RestfulResource::HttpClient::BadGateway)
132
- end
70
+ context 'PUT' do
71
+ include_examples 'raise an exception on error responses', :put
72
+ it 'executes put' do
73
+ connection = faraday_connection do |stubs|
74
+ # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
75
+ stubs.put('http://httpbin.org/put', 'name=Alfred') { |_env| [200, {}, nil] }
76
+ end
133
77
 
134
- it 'post should raise error 502' do
135
- connection = faraday_connection do |stubs|
136
- stubs.post('http://httpbin.org/status/502') { |_env| [502, {}, nil] }
78
+ response = http_client(connection).put('http://httpbin.org/put', data: { name: 'Alfred' })
79
+ expect(response.status).to eq 200
137
80
  end
138
-
139
- expect { http_client(connection).post('http://httpbin.org/status/502') }.to raise_error(RestfulResource::HttpClient::BadGateway)
140
81
  end
141
82
 
142
- it 'patch should raise error 503' do
143
- connection = faraday_connection do |stubs|
144
- stubs.patch('http://httpbin.org/status/503') { |_env| [503, {}, nil] }
145
- end
83
+ context 'POST' do
84
+ include_examples 'raise an exception on error responses', :post
85
+ it 'executes post' do
86
+ connection = faraday_connection do |stubs|
87
+ # Note: request body is serialized as url-encoded so the stub body must be in the same format to match
88
+ stubs.post('http://httpbin.org/post', 'name=Alfred') { |_env| [200, {}, %("name": "Alfred")] }
89
+ end
146
90
 
147
- expect { http_client(connection).patch('http://httpbin.org/status/503') }.to raise_error(RestfulResource::HttpClient::ServiceUnavailable)
148
- end
91
+ response = http_client(connection).post('http://httpbin.org/post', data: { name: 'Alfred' })
149
92
 
150
- it 'put should raise error 503' do
151
- connection = faraday_connection do |stubs|
152
- stubs.put('http://httpbin.org/status/503') { |_env| [503, {}, nil] }
93
+ expect(response.body).to include 'name": "Alfred'
94
+ expect(response.status).to eq 200
153
95
  end
154
-
155
- expect { http_client(connection).put('http://httpbin.org/status/503') }.to raise_error(RestfulResource::HttpClient::ServiceUnavailable)
156
96
  end
157
97
 
158
- it 'post should raise error 503' do
159
- connection = faraday_connection do |stubs|
160
- stubs.post('http://httpbin.org/status/503') { |_env| [503, {}, nil] }
161
- end
162
-
163
- expect { http_client(connection).post('http://httpbin.org/status/503') }.to raise_error(RestfulResource::HttpClient::ServiceUnavailable)
164
- end
98
+ context 'DELETE' do
99
+ include_examples 'raise an exception on error responses', :delete
165
100
 
166
- it 'post should raise error 504' do
167
- connection = faraday_connection do |stubs|
168
- stubs.post('http://httpbin.org/status/504') { |_env| [504, {}, nil] }
169
- end
101
+ it 'executes delete' do
102
+ connection = faraday_connection do |stubs|
103
+ stubs.delete('http://httpbin.org/delete') { |_env| [200, {}, nil] }
104
+ end
170
105
 
171
- expect { http_client(connection).post('http://httpbin.org/status/504') }.to raise_error(RestfulResource::HttpClient::GatewayTimeout)
172
- end
106
+ response = http_client(connection).delete('http://httpbin.org/delete')
173
107
 
174
- it 'raises error on 404' do
175
- connection = faraday_connection do |stubs|
176
- stubs.get('http://httpbin.org/status/404') { |_env| [404, {}, nil] }
177
- stubs.post('http://httpbin.org/status/404') { |_env| [404, {}, nil] }
178
- stubs.patch('http://httpbin.org/status/404') { |_env| [404, {}, nil] }
179
- stubs.put('http://httpbin.org/status/404') { |_env| [404, {}, nil] }
180
- stubs.delete('http://httpbin.org/status/404') { |_env| [404, {}, nil] }
108
+ expect(response.status).to eq 200
181
109
  end
182
-
183
- expect { http_client(connection).get('http://httpbin.org/status/404') }.to raise_error(RestfulResource::HttpClient::ResourceNotFound)
184
- expect { http_client(connection).delete('http://httpbin.org/status/404') }.to raise_error(RestfulResource::HttpClient::ResourceNotFound)
185
- expect { http_client(connection).patch('http://httpbin.org/status/404', data: { name: 'Mad cow' }) }.to raise_error(RestfulResource::HttpClient::ResourceNotFound)
186
- expect { http_client(connection).put('http://httpbin.org/status/404', data: { name: 'Mad cow' }) }.to raise_error(RestfulResource::HttpClient::ResourceNotFound)
187
- expect { http_client(connection).post('http://httpbin.org/status/404', data: { name: 'Mad cow' }) }.to raise_error(RestfulResource::HttpClient::ResourceNotFound)
188
110
  end
189
111
 
190
112
  it 'raises Faraday::ConnectionFailed errors' do
@@ -210,14 +132,6 @@ RSpec.describe RestfulResource::HttpClient do
210
132
 
211
133
  expect { http_client(connection).get('https://localhost:3005') }.to raise_error(RestfulResource::HttpClient::ClientError)
212
134
  end
213
-
214
- it 'raises OtherHttpError for other status response codes' do
215
- connection = faraday_connection do |stubs|
216
- stubs.get('http://httpbin.org/status/418') { |_env| [418, {}, nil] }
217
- end
218
-
219
- expect { http_client(connection).get('http://httpbin.org/status/418') }.to raise_error(RestfulResource::HttpClient::OtherHttpError)
220
- end
221
135
  end
222
136
 
223
137
  describe 'Authentication' do
@@ -338,4 +252,23 @@ RSpec.describe RestfulResource::HttpClient do
338
252
  end
339
253
  end
340
254
  end
255
+
256
+ describe 'X-Client-Start' do
257
+ let(:now) { Time.current }
258
+ let(:required_headers) { { 'X-Client-Start' => (now.to_f * 1000.0).to_i } }
259
+ let(:http_client) { described_class.new(connection: connection) }
260
+ let(:connection) do
261
+ conn = faraday_connection do |stubs|
262
+ stubs.get('http://httpbin.org/get', required_headers) { |_env| [200, {}, nil] }
263
+ end
264
+ end
265
+
266
+ before { allow(Time).to receive(:current).and_return(now) }
267
+
268
+ it 'sets X-Client-Start correctly' do
269
+ response = http_client.get('http://httpbin.org/get')
270
+
271
+ expect(response.status).to eq 200
272
+ end
273
+ end
341
274
  end
@@ -72,13 +72,13 @@ RSpec.describe RestfulResource::RailsValidations do
72
72
  end
73
73
  end
74
74
 
75
- context '#patch without errors' do
75
+ context '#put without errors' do
76
76
  before do
77
77
  data = { name: 'Barak' }
78
78
  expected_response = RestfulResource::Response.new(body: { name: 'Barak' }.to_json)
79
- expect_patch('http://api.carwow.co.uk/dealers/1', expected_response, data: data)
79
+ expect_put('http://api.carwow.co.uk/dealers/1', expected_response, data: data)
80
80
 
81
- @object = Dealer.patch(1, data: data)
81
+ @object = Dealer.put(1, data: data)
82
82
  end
83
83
 
84
84
  it 'returns object' do
@@ -239,4 +239,53 @@ RSpec.describe RestfulResource::RailsValidations do
239
239
  expect(@object.errors).to eq @error
240
240
  end
241
241
  end
242
+
243
+ describe '#delete' do
244
+ subject { Dealer.delete(123) }
245
+
246
+ context 'without errors' do
247
+ before do
248
+ expected_response = RestfulResource::Response.new(body: { name: 'Barak' }.to_json)
249
+ expect_delete('http://api.carwow.co.uk/dealers/123', expected_response)
250
+ end
251
+
252
+ it 'returns object' do
253
+ expect(subject.name).to eq 'Barak'
254
+ end
255
+
256
+ it 'returns valid object' do
257
+ expect(subject).to be_valid
258
+ end
259
+ end
260
+
261
+ context 'with errors' do
262
+ let(:errors) { { errors: ['Cannot use Ninja Turtles names'] } }
263
+
264
+ before do
265
+ expected_response = RestfulResource::Response.new(body: errors.to_json)
266
+ expect_delete_with_unprocessable_entity('http://api.carwow.co.uk/dealers/123', expected_response)
267
+ end
268
+
269
+ it 'has an error' do
270
+ expect(subject.errors.count).to eq 1
271
+ end
272
+
273
+ it 'has correct error' do
274
+ expect(subject.errors.first).to eq 'Cannot use Ninja Turtles names'
275
+ end
276
+
277
+ it 'returns not valid object' do
278
+ expect(subject).not_to be_valid
279
+ end
280
+
281
+ context 'when there is a single error' do
282
+ let(:errors) { 'Cannot use Ninja Turtles names' }
283
+
284
+ it 'handles errors returned as root object' do
285
+ expect(subject).not_to be_valid
286
+ expect(subject.errors).to eq errors
287
+ end
288
+ end
289
+ end
290
+ end
242
291
  end
@@ -1,3 +1,4 @@
1
+ require 'pry'
1
2
  require 'rspec'
2
3
  require 'rspec/its'
3
4
  require_relative '../lib/restful_resource'
@@ -65,3 +66,10 @@ def expect_post_with_unprocessable_entity(url, response, data: {})
65
66
  exception = RestfulResource::HttpClient::UnprocessableEntity.new(request, rest_client_response)
66
67
  expect(@mock_http).to receive(:post).with(url, data: data, headers: {}, open_timeout: nil, timeout: nil).and_raise(exception)
67
68
  end
69
+
70
+ def expect_delete_with_unprocessable_entity(url, response)
71
+ request = RestfulResource::Request.new(:delete, url)
72
+ rest_client_response = OpenStruct.new(body: response.body, headers: response.headers, code: response.status)
73
+ exception = RestfulResource::HttpClient::UnprocessableEntity.new(request, rest_client_response)
74
+ expect(@mock_http).to receive(:delete).with(url, headers: {}, open_timeout: nil, timeout: nil).and_raise(exception)
75
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restful_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.1
4
+ version: 2.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Santoro
8
8
  - Federico Rebora
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-10-03 00:00:00.000000000 Z
12
+ date: 2020-10-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -40,7 +40,7 @@ dependencies:
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
- name: rake
43
+ name: pry
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
@@ -54,7 +54,7 @@ dependencies:
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: rspec
57
+ name: rake
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - ">="
@@ -68,7 +68,7 @@ dependencies:
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: rspec_junit_formatter
71
+ name: rspec
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
@@ -96,47 +96,61 @@ dependencies:
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
- name: activesupport
99
+ name: rspec_junit_formatter
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
- type: :runtime
105
+ type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: activesupport
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '6.0'
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '6.0'
112
126
  - !ruby/object:Gem::Dependency
113
127
  name: faraday
114
128
  requirement: !ruby/object:Gem::Requirement
115
129
  requirements:
116
130
  - - "~>"
117
131
  - !ruby/object:Gem::Version
118
- version: 0.15.0
132
+ version: '1.0'
119
133
  type: :runtime
120
134
  prerelease: false
121
135
  version_requirements: !ruby/object:Gem::Requirement
122
136
  requirements:
123
137
  - - "~>"
124
138
  - !ruby/object:Gem::Version
125
- version: 0.15.0
139
+ version: '1.0'
126
140
  - !ruby/object:Gem::Dependency
127
141
  name: faraday-cdn-metrics
128
142
  requirement: !ruby/object:Gem::Requirement
129
143
  requirements:
130
- - - ">="
144
+ - - "~>"
131
145
  - !ruby/object:Gem::Version
132
- version: '0'
146
+ version: '0.2'
133
147
  type: :runtime
134
148
  prerelease: false
135
149
  version_requirements: !ruby/object:Gem::Requirement
136
150
  requirements:
137
- - - ">="
151
+ - - "~>"
138
152
  - !ruby/object:Gem::Version
139
- version: '0'
153
+ version: '0.2'
140
154
  - !ruby/object:Gem::Dependency
141
155
  name: faraday-encoding
142
156
  requirement: !ruby/object:Gem::Requirement
@@ -155,30 +169,30 @@ dependencies:
155
169
  name: faraday-http-cache
156
170
  requirement: !ruby/object:Gem::Requirement
157
171
  requirements:
158
- - - ">="
172
+ - - "~>"
159
173
  - !ruby/object:Gem::Version
160
- version: '0'
174
+ version: '2.2'
161
175
  type: :runtime
162
176
  prerelease: false
163
177
  version_requirements: !ruby/object:Gem::Requirement
164
178
  requirements:
165
- - - ">="
179
+ - - "~>"
166
180
  - !ruby/object:Gem::Version
167
- version: '0'
181
+ version: '2.2'
168
182
  - !ruby/object:Gem::Dependency
169
183
  name: faraday_middleware
170
184
  requirement: !ruby/object:Gem::Requirement
171
185
  requirements:
172
- - - ">="
186
+ - - "~>"
173
187
  - !ruby/object:Gem::Version
174
- version: '0'
188
+ version: '1.0'
175
189
  type: :runtime
176
190
  prerelease: false
177
191
  version_requirements: !ruby/object:Gem::Requirement
178
192
  requirements:
179
- - - ">="
193
+ - - "~>"
180
194
  - !ruby/object:Gem::Version
181
- version: '0'
195
+ version: '1.0'
182
196
  - !ruby/object:Gem::Dependency
183
197
  name: link_header
184
198
  requirement: !ruby/object:Gem::Requirement
@@ -197,30 +211,30 @@ dependencies:
197
211
  name: rack
198
212
  requirement: !ruby/object:Gem::Requirement
199
213
  requirements:
200
- - - ">="
214
+ - - "~>"
201
215
  - !ruby/object:Gem::Version
202
- version: '0'
216
+ version: '2.2'
203
217
  type: :runtime
204
218
  prerelease: false
205
219
  version_requirements: !ruby/object:Gem::Requirement
206
220
  requirements:
207
- - - ">="
221
+ - - "~>"
208
222
  - !ruby/object:Gem::Version
209
- version: '0'
223
+ version: '2.2'
210
224
  - !ruby/object:Gem::Dependency
211
225
  name: typhoeus
212
226
  requirement: !ruby/object:Gem::Requirement
213
227
  requirements:
214
- - - ">="
228
+ - - "~>"
215
229
  - !ruby/object:Gem::Version
216
- version: '0'
230
+ version: '1.4'
217
231
  type: :runtime
218
232
  prerelease: false
219
233
  version_requirements: !ruby/object:Gem::Requirement
220
234
  requirements:
221
- - - ">="
235
+ - - "~>"
222
236
  - !ruby/object:Gem::Version
223
- version: '0'
237
+ version: '1.4'
224
238
  description: A simple activerecord inspired rest resource base class implemented using
225
239
  rest-client
226
240
  email:
@@ -274,7 +288,7 @@ homepage: http://www.github.com/carwow/restful_resource
274
288
  licenses:
275
289
  - MIT
276
290
  metadata: {}
277
- post_install_message:
291
+ post_install_message:
278
292
  rdoc_options: []
279
293
  require_paths:
280
294
  - lib
@@ -289,8 +303,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
289
303
  - !ruby/object:Gem::Version
290
304
  version: '0'
291
305
  requirements: []
292
- rubygems_version: 3.0.3
293
- signing_key:
306
+ rubygems_version: 3.1.2
307
+ signing_key:
294
308
  specification_version: 4
295
309
  summary: A simple activerecord inspired rest resource base class implemented using
296
310
  rest-client