active_rest_client 0.9.75 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/CONTRIBUTING.md +62 -0
- data/README.md +1 -1
- data/doc/ActiveRestClient Internals.graffle +1236 -0
- data/doc/ActiveRestClient Internals.png +0 -0
- data/lib/active_rest_client/caching.rb +1 -1
- data/lib/active_rest_client/mapping.rb +4 -0
- data/lib/active_rest_client/request.rb +81 -52
- data/lib/active_rest_client/version.rb +1 -1
- data/spec/lib/mapping_spec.rb +6 -2
- data/spec/lib/request_spec.rb +62 -8
- metadata +6 -3
Binary file
|
@@ -46,7 +46,7 @@ module ActiveRestClient
|
|
46
46
|
def read_cached_response(request)
|
47
47
|
if cache_store && perform_caching
|
48
48
|
key = "#{request.class_name}:#{request.original_url}"
|
49
|
-
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{key} -
|
49
|
+
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{key} - Trying to read from cache"
|
50
50
|
value = cache_store.read(key)
|
51
51
|
value = Marshal.load(value) rescue value
|
52
52
|
end
|
@@ -17,6 +17,10 @@ module ActiveRestClient
|
|
17
17
|
_map_call(name, url:url, method: :delete, options:options)
|
18
18
|
end
|
19
19
|
|
20
|
+
def patch(name, url, options = {})
|
21
|
+
_map_call(name, url:url, method: :patch, options:options)
|
22
|
+
end
|
23
|
+
|
20
24
|
def _map_call(name, details)
|
21
25
|
_calls[name] = {name:name}.merge(details)
|
22
26
|
_calls["lazy_#{name}".to_sym] = {name:name}.merge(details)
|
@@ -114,6 +114,11 @@ module ActiveRestClient
|
|
114
114
|
elsif cached.etag.to_s != "" #present? isn't working for some reason
|
115
115
|
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Etag cached copy found with etag #{cached.etag}"
|
116
116
|
etag = cached.etag
|
117
|
+
response = do_request(etag)
|
118
|
+
if response.status == 304
|
119
|
+
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response status 304. Copy is still fresh"
|
120
|
+
return handle_cached_response(cached)
|
121
|
+
end
|
117
122
|
end
|
118
123
|
end
|
119
124
|
response = if proxy
|
@@ -224,11 +229,12 @@ module ActiveRestClient
|
|
224
229
|
|
225
230
|
if verbose?
|
226
231
|
ActiveRestClient::Logger.debug "ActiveRestClient Verbose Log:"
|
227
|
-
ActiveRestClient::Logger.debug "
|
232
|
+
ActiveRestClient::Logger.debug " Request"
|
233
|
+
ActiveRestClient::Logger.debug " >> GET #{@url} HTTP/1.1"
|
228
234
|
http_headers.each do |k,v|
|
229
|
-
ActiveRestClient::Logger.debug "
|
235
|
+
ActiveRestClient::Logger.debug " >> #{k} : #{v}"
|
230
236
|
end
|
231
|
-
ActiveRestClient::Logger.debug "
|
237
|
+
ActiveRestClient::Logger.debug " >> Body:\n#{@body}"
|
232
238
|
end
|
233
239
|
|
234
240
|
case http_method
|
@@ -245,10 +251,12 @@ module ActiveRestClient
|
|
245
251
|
end
|
246
252
|
|
247
253
|
if verbose?
|
254
|
+
ActiveRestClient::Logger.debug " Response"
|
255
|
+
ActiveRestClient::Logger.debug " << Status : #{response.status}"
|
248
256
|
response.headers.each do |k,v|
|
249
|
-
ActiveRestClient::Logger.debug "
|
257
|
+
ActiveRestClient::Logger.debug " << #{k} : #{v}"
|
250
258
|
end
|
251
|
-
ActiveRestClient::Logger.debug "
|
259
|
+
ActiveRestClient::Logger.debug " << Body:\n#{response.body}"
|
252
260
|
end
|
253
261
|
|
254
262
|
response
|
@@ -268,62 +276,49 @@ module ActiveRestClient
|
|
268
276
|
end
|
269
277
|
|
270
278
|
def handle_response(response)
|
271
|
-
if response.status == 304
|
272
|
-
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Etag copy is the same as the server"
|
273
|
-
return :not_modified
|
274
|
-
end
|
275
|
-
if response.respond_to?(:proxied) && response.proxied
|
276
|
-
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response was proxied, unable to determine size"
|
277
|
-
else
|
278
|
-
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response received #{response.body.size} bytes"
|
279
|
-
end
|
280
|
-
|
281
|
-
if @method[:options][:plain]
|
282
|
-
return @response = response.body
|
283
|
-
end
|
284
|
-
|
285
279
|
@response = response
|
280
|
+
@response.status ||= 200
|
286
281
|
|
287
|
-
if
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
result
|
282
|
+
if (200..399).include? @response.status
|
283
|
+
if response.status == 304
|
284
|
+
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Etag copy is the same as the server"
|
285
|
+
return :not_modified
|
286
|
+
end
|
287
|
+
if @method[:options][:plain]
|
288
|
+
return @response = response.body
|
289
|
+
elsif is_json_response?
|
290
|
+
if @response.respond_to?(:proxied) && @response.proxied
|
291
|
+
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response was proxied, unable to determine size"
|
292
|
+
else
|
293
|
+
ActiveRestClient::Logger.debug " \033[1;4;32m#{ActiveRestClient::NAME}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
|
294
|
+
end
|
295
|
+
result = generate_new_object
|
296
|
+
else
|
297
|
+
raise ResponseParseException.new(status:@response.status, body:@response.body)
|
301
298
|
end
|
302
299
|
else
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
@
|
307
|
-
|
300
|
+
if is_json_response?
|
301
|
+
error_response = generate_new_object(mutable: false)
|
302
|
+
else
|
303
|
+
error_response = @response.body
|
304
|
+
end
|
305
|
+
if @response.status == 400
|
306
|
+
raise HTTPBadRequestClientException.new(status:@response.status, result:error_response, url:@url)
|
307
|
+
elsif @response.status == 401
|
308
|
+
raise HTTPUnauthorisedClientException.new(status:@response.status, result:error_response, url:@url)
|
309
|
+
elsif @response.status == 403
|
310
|
+
raise HTTPForbiddenClientException.new(status:@response.status, result:error_response, url:@url)
|
311
|
+
elsif @response.status == 404
|
312
|
+
raise HTTPNotFoundClientException.new(status:@response.status, result:error_response, url:@url)
|
313
|
+
elsif (400..499).include? @response.status
|
314
|
+
raise HTTPClientException.new(status:@response.status, result:error_response, url:@url)
|
315
|
+
elsif (500..599).include? @response.status
|
316
|
+
raise HTTPServerException.new(status:@response.status, result:error_response, url:@url)
|
308
317
|
end
|
309
318
|
end
|
310
319
|
|
311
|
-
response.status ||= 200
|
312
|
-
if response.status == 401
|
313
|
-
raise HTTPUnauthorisedClientException.new(status:response.status, result:result, url:@url)
|
314
|
-
elsif response.status == 403
|
315
|
-
raise HTTPForbiddenClientException.new(status:response.status, result:result, url:@url)
|
316
|
-
elsif response.status == 404
|
317
|
-
raise HTTPNotFoundClientException.new(status:response.status, result:result, url:@url)
|
318
|
-
elsif (400..499).include? response.status
|
319
|
-
raise HTTPClientException.new(status:response.status, result:result, url:@url)
|
320
|
-
elsif (500..599).include? response.status
|
321
|
-
raise HTTPServerException.new(status:response.status, result:result, url:@url)
|
322
|
-
end
|
323
320
|
|
324
321
|
result
|
325
|
-
rescue MultiJson::ParseError
|
326
|
-
raise ResponseParseException.new(status:response.status, body:response.body)
|
327
322
|
end
|
328
323
|
|
329
324
|
def new_object(attributes, name = nil)
|
@@ -418,6 +413,39 @@ module ActiveRestClient
|
|
418
413
|
|
419
414
|
attributes
|
420
415
|
end
|
416
|
+
|
417
|
+
private
|
418
|
+
|
419
|
+
def is_json_response?
|
420
|
+
@response.headers['Content-Type'].nil? || @response.headers['Content-Type'].include?('json')
|
421
|
+
end
|
422
|
+
|
423
|
+
def generate_new_object(options={})
|
424
|
+
if @response.body.is_a?(Array) || @response.body.is_a?(Hash)
|
425
|
+
body = @response.body
|
426
|
+
else
|
427
|
+
body = MultiJson.load(@response.body) || {}
|
428
|
+
end
|
429
|
+
body = begin
|
430
|
+
@method[:name].nil? ? body : translator.send(@method[:name], body)
|
431
|
+
rescue NoMethodError
|
432
|
+
body
|
433
|
+
end
|
434
|
+
if body.is_a? Array
|
435
|
+
result = ActiveRestClient::ResultIterator.new(@response.status)
|
436
|
+
body.each do |json_object|
|
437
|
+
result << new_object(json_object, @overriden_name)
|
438
|
+
end
|
439
|
+
else
|
440
|
+
result = new_object(body, @overriden_name)
|
441
|
+
result._status = @response.status
|
442
|
+
if !object_is_class? && options[:mutable] != false
|
443
|
+
@object._copy_from(result)
|
444
|
+
result = @object
|
445
|
+
end
|
446
|
+
end
|
447
|
+
result
|
448
|
+
end
|
421
449
|
end
|
422
450
|
|
423
451
|
class RequestException < StandardError ; end
|
@@ -441,6 +469,7 @@ module ActiveRestClient
|
|
441
469
|
end
|
442
470
|
class HTTPClientException < HTTPException ; end
|
443
471
|
class HTTPUnauthorisedClientException < HTTPClientException ; end
|
472
|
+
class HTTPBadRequestClientException < HTTPClientException ; end
|
444
473
|
class HTTPForbiddenClientException < HTTPClientException ; end
|
445
474
|
class HTTPNotFoundClientException < HTTPClientException ; end
|
446
475
|
class HTTPServerException < HTTPException ; end
|
data/spec/lib/mapping_spec.rb
CHANGED
@@ -8,7 +8,8 @@ class MappingExample < MappingExampleBase
|
|
8
8
|
get :test_get, "/get", tag:1, fake:"{result:true}", lazy:[:something]
|
9
9
|
put :test_put, "/put", tag:2
|
10
10
|
post :test_post, "/post", tag:3
|
11
|
-
|
11
|
+
patch :test_patch, "/patch", tag:4
|
12
|
+
delete :test_delete, "/delete", tag:5
|
12
13
|
end
|
13
14
|
|
14
15
|
describe ActiveRestClient::Mapping do
|
@@ -23,6 +24,7 @@ describe ActiveRestClient::Mapping do
|
|
23
24
|
expect(MappingExample._calls[:test_get][:url]).to eq("/get")
|
24
25
|
expect(MappingExample._calls[:test_put][:url]).to eq("/put")
|
25
26
|
expect(MappingExample._calls[:test_post][:url]).to eq("/post")
|
27
|
+
expect(MappingExample._calls[:test_patch][:url]).to eq("/patch")
|
26
28
|
expect(MappingExample._calls[:test_delete][:url]).to eq("/delete")
|
27
29
|
end
|
28
30
|
|
@@ -30,6 +32,7 @@ describe ActiveRestClient::Mapping do
|
|
30
32
|
expect(MappingExample._calls[:test_get][:method]).to eq(:get)
|
31
33
|
expect(MappingExample._calls[:test_put][:method]).to eq(:put)
|
32
34
|
expect(MappingExample._calls[:test_post][:method]).to eq(:post)
|
35
|
+
expect(MappingExample._calls[:test_patch][:method]).to eq(:patch)
|
33
36
|
expect(MappingExample._calls[:test_delete][:method]).to eq(:delete)
|
34
37
|
end
|
35
38
|
|
@@ -39,7 +42,8 @@ describe ActiveRestClient::Mapping do
|
|
39
42
|
expect(MappingExample._calls[:test_get][:options][:tag]).to eq(1)
|
40
43
|
expect(MappingExample._calls[:test_put][:options][:tag]).to eq(2)
|
41
44
|
expect(MappingExample._calls[:test_post][:options][:tag]).to eq(3)
|
42
|
-
expect(MappingExample._calls[:
|
45
|
+
expect(MappingExample._calls[:test_patch][:options][:tag]).to eq(4)
|
46
|
+
expect(MappingExample._calls[:test_delete][:options][:tag]).to eq(5)
|
43
47
|
end
|
44
48
|
|
45
49
|
it "should allow for mapped calls on the class" do
|
data/spec/lib/request_spec.rb
CHANGED
@@ -233,8 +233,8 @@ describe ActiveRestClient::Request do
|
|
233
233
|
ActiveRestClient::ConnectionManager.should_receive(:get_connection).and_return(connection)
|
234
234
|
connection.should_receive(:get).with("/all", an_instance_of(Hash)).and_return(OpenStruct.new(body:'{"result":true}', headers:{"Content-Type" => "application/json", "Connection" => "close"}))
|
235
235
|
ActiveRestClient::Logger.should_receive(:debug).with("ActiveRestClient Verbose Log:")
|
236
|
-
ActiveRestClient::Logger.should_receive(:debug).with(/
|
237
|
-
ActiveRestClient::Logger.should_receive(:debug).with(/
|
236
|
+
ActiveRestClient::Logger.should_receive(:debug).with(/ >> /).at_least(:twice)
|
237
|
+
ActiveRestClient::Logger.should_receive(:debug).with(/ << /).at_least(:twice)
|
238
238
|
ActiveRestClient::Logger.stub(:debug).with(any_args)
|
239
239
|
VerboseExampleClient.all
|
240
240
|
end
|
@@ -270,7 +270,7 @@ describe ActiveRestClient::Request do
|
|
270
270
|
end
|
271
271
|
expect(e).to be_instance_of(ActiveRestClient::HTTPForbiddenClientException)
|
272
272
|
expect(e.status).to eq(403)
|
273
|
-
|
273
|
+
expect(e.result.first_name).to eq("John")
|
274
274
|
end
|
275
275
|
|
276
276
|
it "should raise a not found client exception for 404 errors" do
|
@@ -304,7 +304,7 @@ describe ActiveRestClient::Request do
|
|
304
304
|
end
|
305
305
|
expect(e).to be_instance_of(ActiveRestClient::HTTPClientException)
|
306
306
|
expect(e.status).to eq(409)
|
307
|
-
|
307
|
+
expect(e.result.first_name).to eq("John")
|
308
308
|
end
|
309
309
|
|
310
310
|
it "should raise a server exception for 5xx errors" do
|
@@ -330,25 +330,79 @@ describe ActiveRestClient::Request do
|
|
330
330
|
any_instance.
|
331
331
|
should_receive(:post).
|
332
332
|
with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
|
333
|
-
and_return(OpenStruct.new(body:error_content, headers:{}, status:500))
|
333
|
+
and_return(OpenStruct.new(body:error_content, headers:{'Content-Type' => 'text/html'}, status:500))
|
334
334
|
object = ExampleClient.new(first_name:"John", should_disappear:true)
|
335
335
|
begin
|
336
336
|
object.create
|
337
|
-
rescue
|
337
|
+
rescue => e
|
338
338
|
e
|
339
339
|
end
|
340
|
-
expect(e).to be_instance_of(ActiveRestClient::
|
340
|
+
expect(e).to be_instance_of(ActiveRestClient::HTTPServerException)
|
341
341
|
expect(e.status).to eq(500)
|
342
|
+
expect(e.result).to eq(error_content)
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should raise a bad request exception for 400 response status" do
|
346
|
+
error_content = "<h1>400 Bad Request</h1>"
|
347
|
+
ActiveRestClient::Connection.
|
348
|
+
any_instance.
|
349
|
+
should_receive(:post).
|
350
|
+
with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
|
351
|
+
and_return(OpenStruct.new(body:error_content, headers:{'Content-Type' => 'text/html'}, status:400))
|
352
|
+
object = ExampleClient.new(first_name:"John", should_disappear:true)
|
353
|
+
begin
|
354
|
+
object.create
|
355
|
+
rescue => e
|
356
|
+
e
|
357
|
+
end
|
358
|
+
expect(e).to be_instance_of(ActiveRestClient::HTTPBadRequestClientException)
|
359
|
+
expect(e.status).to eq(400)
|
360
|
+
expect(e.result).to eq(error_content)
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should raise response parse exception for 200 response status and non json content type" do
|
364
|
+
error_content = "<h1>malformed json</h1>"
|
365
|
+
ActiveRestClient::Connection.
|
366
|
+
any_instance.
|
367
|
+
should_receive(:post).
|
368
|
+
with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
|
369
|
+
and_return(OpenStruct.new(body:error_content, headers:{'Content-Type' => 'text/html'}, status:200))
|
370
|
+
object = ExampleClient.new(first_name:"John", should_disappear:true)
|
371
|
+
begin
|
372
|
+
object.create
|
373
|
+
rescue => e
|
374
|
+
e
|
375
|
+
end
|
376
|
+
expect(e).to be_instance_of(ActiveRestClient::ResponseParseException)
|
377
|
+
expect(e.status).to eq(200)
|
342
378
|
expect(e.body).to eq(error_content)
|
343
379
|
end
|
344
380
|
|
381
|
+
it "should not override the attributes of the existing object on error response status" do
|
382
|
+
ActiveRestClient::Connection.
|
383
|
+
any_instance.
|
384
|
+
should_receive(:post).
|
385
|
+
with("/create", "first_name=John&should_disappear=true", an_instance_of(Hash)).
|
386
|
+
and_return(OpenStruct.new(body:'{"errors": ["validation": "error in validation"]}', headers:{'Content-Type' => 'text/html'}, status:400))
|
387
|
+
object = ExampleClient.new(first_name:"John", should_disappear:true)
|
388
|
+
begin
|
389
|
+
object.create
|
390
|
+
rescue => e
|
391
|
+
e
|
392
|
+
end
|
393
|
+
expect(e).to be_instance_of(ActiveRestClient::HTTPBadRequestClientException)
|
394
|
+
expect(e.status).to eq(400)
|
395
|
+
expect(object.first_name).to eq 'John'
|
396
|
+
expect(object.errors).to be_nil
|
397
|
+
end
|
398
|
+
|
345
399
|
it "should raise an exception if you try to pass in an unsupport method" do
|
346
400
|
method = {:method => :wiggle, url:"/"}
|
347
401
|
class RequestFakeObject
|
348
402
|
def request_body_type
|
349
403
|
:form_encoded
|
350
404
|
end
|
351
|
-
|
405
|
+
|
352
406
|
def base_url
|
353
407
|
"http://www.example.com/"
|
354
408
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_rest_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Which Ltd
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-04-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -219,12 +219,15 @@ files:
|
|
219
219
|
- ".rspec"
|
220
220
|
- ".simplecov"
|
221
221
|
- ".travis.yml"
|
222
|
+
- CONTRIBUTING.md
|
222
223
|
- Gemfile
|
223
224
|
- Guardfile
|
224
225
|
- LICENSE.txt
|
225
226
|
- README.md
|
226
227
|
- Rakefile
|
227
228
|
- active_rest_client.gemspec
|
229
|
+
- doc/ActiveRestClient Internals.graffle
|
230
|
+
- doc/ActiveRestClient Internals.png
|
228
231
|
- lib/active_rest_client.rb
|
229
232
|
- lib/active_rest_client/base.rb
|
230
233
|
- lib/active_rest_client/caching.rb
|
@@ -282,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
282
285
|
version: '0'
|
283
286
|
requirements: []
|
284
287
|
rubyforge_project:
|
285
|
-
rubygems_version: 2.2.
|
288
|
+
rubygems_version: 2.2.2
|
286
289
|
signing_key:
|
287
290
|
specification_version: 4
|
288
291
|
summary: This gem is for accessing REST services in an ActiveRecord style. ActiveResource
|