restful_resource 2.6.1 → 2.10.1

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