rest 1.2.2 → 2.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.
- data/Gemfile.lock +6 -2
- data/README.md +27 -2
- data/Rakefile +1 -0
- data/lib/rest/client.rb +66 -43
- data/lib/rest/errors.rb +43 -0
- data/lib/rest/version.rb +1 -1
- data/lib/rest/wrappers/base_wrapper.rb +44 -20
- data/lib/rest/wrappers/excon_wrapper.rb +111 -0
- data/lib/rest/wrappers/net_http_persistent_wrapper.rb +37 -21
- data/lib/rest/wrappers/rest_client_wrapper.rb +12 -6
- data/lib/rest/wrappers/typhoeus_wrapper.rb +34 -20
- data/rest.gemspec +3 -1
- data/test/test_base.rb +9 -4
- data/test/test_performance.rb +5 -4
- data/test/test_rest.rb +68 -5
- data/test/tmp.rb +24 -11
- metadata +37 -3
data/Gemfile.lock
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rest (1.2.
|
4
|
+
rest (1.2.2)
|
5
|
+
net-http-persistent
|
5
6
|
rest-client (>= 0.3.0)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
11
|
+
excon (0.14.3)
|
10
12
|
ffi (1.0.11)
|
11
13
|
mime-types (1.19)
|
14
|
+
minitest (3.2.0)
|
12
15
|
net-http-persistent (2.7)
|
13
16
|
quicky (0.0.1)
|
14
17
|
rake (0.9.2.2)
|
@@ -24,7 +27,8 @@ PLATFORMS
|
|
24
27
|
ruby
|
25
28
|
|
26
29
|
DEPENDENCIES
|
27
|
-
|
30
|
+
excon
|
31
|
+
minitest
|
28
32
|
quicky
|
29
33
|
rake
|
30
34
|
rest!
|
data/README.md
CHANGED
@@ -1,8 +1,22 @@
|
|
1
1
|
Rest Wrapper
|
2
2
|
-------------
|
3
3
|
|
4
|
-
HTTP/REST client wrapper that provides a standard interface for making http requests using different http
|
5
|
-
If no client is specified it will choose the best
|
4
|
+
HTTP/REST client wrapper that provides a standard interface for making http requests using different http
|
5
|
+
clients. If no client is specified **it will choose the best http client** you have installed based on
|
6
|
+
our performance tests.
|
7
|
+
|
8
|
+
Features
|
9
|
+
========
|
10
|
+
|
11
|
+
* All clients behave exactly the same:
|
12
|
+
* Same error behavior
|
13
|
+
* Same 30X redirect behavior
|
14
|
+
* Same response object methods
|
15
|
+
* Same way to access and manipulate requests and responses such as body, headers, code, etc.
|
16
|
+
* Chooses best client you have installed on your system based on what we have found performs the best.
|
17
|
+
* Currently net_http_persistent and typhoeus are nearly the same, but since net_http_persistent doesn't have a binary
|
18
|
+
dependency, it wins.
|
19
|
+
|
6
20
|
|
7
21
|
Getting Started
|
8
22
|
==============
|
@@ -70,3 +84,14 @@ The response object you get back will always be consistent and will have the fol
|
|
70
84
|
response.code
|
71
85
|
response.body
|
72
86
|
|
87
|
+
|
88
|
+
Exceptions
|
89
|
+
======
|
90
|
+
|
91
|
+
If it didn't get a response for whatever reason, you will get a Rest::ClientError
|
92
|
+
|
93
|
+
If status code is 40X or 50X, it will raise an exception with the following methods.
|
94
|
+
|
95
|
+
err.code
|
96
|
+
err.response (which has body: err.response.body)
|
97
|
+
|
data/Rakefile
CHANGED
data/lib/rest/client.rb
CHANGED
@@ -5,26 +5,12 @@ require 'logger'
|
|
5
5
|
# The purpose of this is so that users who can't install binaries easily (like windoze users)
|
6
6
|
# can have fallbacks that work.
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
class ClientError < StandardError
|
11
|
-
|
12
|
-
end
|
8
|
+
require_relative 'errors'
|
13
9
|
|
14
|
-
|
15
|
-
class TimeoutError < ClientError
|
16
|
-
def initialize(msg=nil)
|
17
|
-
msg ||= "HTTP Request Timed out."
|
18
|
-
super(msg)
|
19
|
-
end
|
20
|
-
end
|
10
|
+
module Rest
|
21
11
|
|
22
12
|
require_relative 'wrappers/base_wrapper'
|
23
13
|
|
24
|
-
#def self.puts(s)
|
25
|
-
# Kernel.puts("rest gem: #{s}")
|
26
|
-
#end
|
27
|
-
|
28
14
|
class Client
|
29
15
|
|
30
16
|
attr_accessor :options, :logger, :gem
|
@@ -42,7 +28,11 @@ module Rest
|
|
42
28
|
choose_best_gem()
|
43
29
|
end
|
44
30
|
|
45
|
-
if @gem == :
|
31
|
+
if @gem == :excon
|
32
|
+
require_relative 'wrappers/excon_wrapper'
|
33
|
+
@wrapper = Rest::Wrappers::ExconWrapper.new(self)
|
34
|
+
@logger.debug "Using excon gem."
|
35
|
+
elsif @gem == :typhoeus
|
46
36
|
require_relative 'wrappers/typhoeus_wrapper'
|
47
37
|
@wrapper = Rest::Wrappers::TyphoeusWrapper.new
|
48
38
|
@logger.debug "Using typhoeus gem."
|
@@ -60,13 +50,13 @@ module Rest
|
|
60
50
|
def choose_best_gem
|
61
51
|
begin
|
62
52
|
raise LoadError
|
63
|
-
|
64
|
-
|
53
|
+
require 'typhoeus'
|
54
|
+
@gem = :typhoeus
|
65
55
|
rescue LoadError => ex
|
66
56
|
begin
|
67
57
|
# try net-http-persistent
|
68
|
-
|
69
|
-
|
58
|
+
require 'net/http/persistent'
|
59
|
+
@gem = :net_http_persistent
|
70
60
|
rescue LoadError => ex
|
71
61
|
end
|
72
62
|
end
|
@@ -78,7 +68,7 @@ module Rest
|
|
78
68
|
|
79
69
|
def get(url, req_hash={})
|
80
70
|
res = nil
|
81
|
-
perform_op do
|
71
|
+
res = perform_op(:get, req_hash) do
|
82
72
|
res = @wrapper.get(url, req_hash)
|
83
73
|
end
|
84
74
|
return res
|
@@ -86,38 +76,71 @@ module Rest
|
|
86
76
|
|
87
77
|
# This will attempt to perform the operation with an exponential backoff on 503 errors.
|
88
78
|
# Amazon services throw 503
|
89
|
-
|
90
|
-
|
79
|
+
# todo: just make perform_op a method and have it call the wrapper. The block is a waste now.
|
80
|
+
def perform_op(method, req_hash, options={}, &blk)
|
81
|
+
set_defaults(options)
|
82
|
+
max_retries = options[:max_retries] || 5
|
83
|
+
max_follows = options[:max_follows] || 10
|
84
|
+
if options[:follow_count] && options[:follow_count] >= max_follows
|
85
|
+
raise Rest::RestError "Too many follows. #{options[:follow_count]}"
|
86
|
+
end
|
91
87
|
current_retry = 0
|
88
|
+
current_follow = 0
|
92
89
|
success = false
|
93
90
|
res = nil
|
94
|
-
while current_retry < max_retries do
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
91
|
+
while current_retry < max_retries && current_follow < max_follows do
|
92
|
+
begin
|
93
|
+
res = yield blk
|
94
|
+
res.tries = current_retry + 1
|
95
|
+
if res.code >= 300 && res.code < 400
|
96
|
+
# try new location
|
97
|
+
#p res.headers
|
98
|
+
loc = res.headers["location"]
|
99
|
+
@logger.debug "#{res.code} Received. Trying new location: #{loc}"
|
100
|
+
if loc.nil?
|
101
|
+
raise InvalidResponseError.new("No location header received with #{res.code} status code!")
|
102
|
+
end
|
103
|
+
# options.merge({:max_follows=>options[:max_follows-1]}
|
104
|
+
options[:follow_count] ||= 0
|
105
|
+
options[:follow_count] += 1
|
106
|
+
res = perform_op(method, req_hash, options) do
|
107
|
+
res = @wrapper.send(method, loc, req_hash)
|
108
|
+
end
|
109
|
+
#puts 'X: ' + res.inspect
|
110
|
+
return res
|
111
|
+
end
|
112
|
+
# If it's here, then it's all good
|
109
113
|
break
|
114
|
+
rescue Rest::HttpError => ex
|
115
|
+
if ex.code == 503
|
116
|
+
pow = (4 ** (current_retry)) * 100 # milliseconds
|
117
|
+
#puts 'pow=' + pow.to_s
|
118
|
+
s = Random.rand * pow
|
119
|
+
#puts 's=' + s.to_s
|
120
|
+
sleep_secs = 1.0 * s / 1000.0
|
121
|
+
#puts 'sleep for ' + sleep_secs.to_s
|
122
|
+
current_retry += 1
|
123
|
+
@logger.debug "#{ex.code} Received. Retrying #{current_retry} out of #{max_retries} max in #{sleep_secs} seconds."
|
124
|
+
sleep sleep_secs
|
125
|
+
else
|
126
|
+
raise ex
|
127
|
+
end
|
110
128
|
end
|
111
129
|
end
|
112
130
|
res
|
113
131
|
end
|
114
132
|
|
133
|
+
def set_defaults(options)
|
134
|
+
options[:max_retries] ||= (@options[:max_retries] || 5)
|
135
|
+
options[:max_follows] ||= (@options[:max_follows] || 10)
|
136
|
+
end
|
137
|
+
|
115
138
|
# req_hash options:
|
116
139
|
# - :body => post body
|
117
140
|
#
|
118
141
|
def post(url, req_hash={})
|
119
142
|
res = nil
|
120
|
-
perform_op do
|
143
|
+
res = perform_op(:post, req_hash) do
|
121
144
|
res = @wrapper.post(url, req_hash)
|
122
145
|
end
|
123
146
|
return res
|
@@ -125,7 +148,7 @@ module Rest
|
|
125
148
|
|
126
149
|
def put(url, req_hash={})
|
127
150
|
res = nil
|
128
|
-
perform_op do
|
151
|
+
res = perform_op(:put, req_hash) do
|
129
152
|
res = @wrapper.put(url, req_hash)
|
130
153
|
end
|
131
154
|
return res
|
@@ -133,7 +156,7 @@ module Rest
|
|
133
156
|
|
134
157
|
def delete(url, req_hash={})
|
135
158
|
res = nil
|
136
|
-
perform_op do
|
159
|
+
res = perform_op(:delete, req_hash) do
|
137
160
|
res = @wrapper.delete(url, req_hash)
|
138
161
|
end
|
139
162
|
return res
|
@@ -141,7 +164,7 @@ module Rest
|
|
141
164
|
|
142
165
|
def post_file(url, req_hash={})
|
143
166
|
res = nil
|
144
|
-
perform_op do
|
167
|
+
res = perform_op(:post_file, req_hash) do
|
145
168
|
res = @wrapper.post_file(url, req_hash)
|
146
169
|
end
|
147
170
|
return res
|
data/lib/rest/errors.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
module Rest
|
3
|
+
|
4
|
+
# Base Rest error class
|
5
|
+
class RestError < StandardError
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
class HttpError < RestError
|
10
|
+
def initialize(response)
|
11
|
+
super("#{response.code} Error")
|
12
|
+
@response = response
|
13
|
+
end
|
14
|
+
|
15
|
+
def response
|
16
|
+
@response
|
17
|
+
end
|
18
|
+
def code
|
19
|
+
response.code
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"HTTP #{code} Error. #{response.body}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# If it didn't even get a response, it will be a ClientError
|
28
|
+
class ClientError < RestError
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class TimeoutError < ClientError
|
33
|
+
def initialize(msg=nil)
|
34
|
+
msg ||= "HTTP Request Timed out."
|
35
|
+
super(msg)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class InvalidResponseError < RestError
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
data/lib/rest/version.rb
CHANGED
@@ -1,29 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
module Rest
|
2
|
+
class BaseWrapper
|
3
|
+
|
4
|
+
def post_file(url, req_hash={})
|
5
|
+
response = nil
|
6
|
+
begin
|
7
|
+
if req_hash[:body]
|
8
|
+
req_hash = req_hash.merge(req_hash[:body])
|
9
|
+
req_hash.delete(:body)
|
10
|
+
end
|
11
|
+
|
12
|
+
headers = {}
|
13
|
+
if req_hash[:headers]
|
14
|
+
headers = req_hash[:headers]
|
15
|
+
req_hash.delete(:headers)
|
16
|
+
end
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
r2 = RestClient.post(url, req_hash, headers)
|
19
|
+
response = Rest::Wrappers::RestClientResponseWrapper.new(r2)
|
20
|
+
rescue RestClient::Exception => ex
|
21
|
+
raise Rest::Wrappers::RestClientExceptionWrapper.new(ex)
|
15
22
|
end
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
# if body is a hash, it will convert it to json
|
27
|
+
def to_json_parts(h)
|
28
|
+
h[:body] = h[:body].to_json if h[:body] && h[:body].is_a?(Hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
# if wrapper has a close/shutdown, override this
|
32
|
+
def close
|
16
33
|
|
17
|
-
r2 = RestClient.post(url, req_hash, headers)
|
18
|
-
response = Rest::Wrappers::RestClientResponseWrapper.new(r2)
|
19
|
-
rescue RestClient::Exception => ex
|
20
|
-
raise Rest::Wrappers::RestClientExceptionWrapper.new(ex)
|
21
34
|
end
|
22
|
-
response
|
23
35
|
end
|
24
36
|
|
25
|
-
|
26
|
-
|
37
|
+
class BaseResponseWrapper
|
38
|
+
attr_accessor :tries
|
39
|
+
|
40
|
+
# Provide a headers_orig method in your wrapper to allow this to work
|
41
|
+
def headers
|
42
|
+
new_h = {}
|
43
|
+
headers_orig.each_pair do |k,v|
|
44
|
+
if v.is_a?(Array) && v.size == 1
|
45
|
+
v = v[0]
|
46
|
+
end
|
47
|
+
new_h[k.downcase] = v
|
48
|
+
end
|
49
|
+
new_h
|
50
|
+
end
|
27
51
|
|
28
52
|
end
|
29
53
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'excon'
|
2
|
+
|
3
|
+
module Rest
|
4
|
+
|
5
|
+
module Wrappers
|
6
|
+
class ExconExceptionWrapper < ClientError
|
7
|
+
def initialize(ex)
|
8
|
+
super(ex.message)
|
9
|
+
@ex = ex
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ExconResponseWrapper < BaseResponseWrapper
|
14
|
+
def initialize(response)
|
15
|
+
@response = response
|
16
|
+
end
|
17
|
+
|
18
|
+
def code
|
19
|
+
@response.status
|
20
|
+
end
|
21
|
+
|
22
|
+
def body
|
23
|
+
@response.body
|
24
|
+
end
|
25
|
+
|
26
|
+
def headers_orig
|
27
|
+
@response.headers
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class ExconWrapper < BaseWrapper
|
33
|
+
|
34
|
+
def initialize(client)
|
35
|
+
@client = client
|
36
|
+
# Would need to pass in base url to use persistent connection.
|
37
|
+
#@http = Excon.new("")
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_headers
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(url, req_hash={})
|
45
|
+
response = nil
|
46
|
+
begin
|
47
|
+
uri = URI(url)
|
48
|
+
req_hash[:method] = :get
|
49
|
+
req_hash[:url] = url
|
50
|
+
req_hash[:headers] ||= default_headers
|
51
|
+
req_hash[:query] = req_hash[:params] if req_hash[:params]
|
52
|
+
#p req_hash
|
53
|
+
response = excon_request(url, req_hash)
|
54
|
+
rescue RestClient::Exception => ex
|
55
|
+
#p ex
|
56
|
+
raise ExconExceptionWrapper.new(ex)
|
57
|
+
end
|
58
|
+
response
|
59
|
+
end
|
60
|
+
|
61
|
+
def excon_request(url, req_hash)
|
62
|
+
conn = Excon.new(url)
|
63
|
+
r2 = conn.request(req_hash)
|
64
|
+
response = ExconResponseWrapper.new(r2)
|
65
|
+
if response.code >= 400
|
66
|
+
raise HttpError.new(response)
|
67
|
+
end
|
68
|
+
response
|
69
|
+
end
|
70
|
+
|
71
|
+
def post(url, req_hash={})
|
72
|
+
response = nil
|
73
|
+
begin
|
74
|
+
req_hash[:method] = :post
|
75
|
+
req_hash[:url] = url
|
76
|
+
to_json_parts(req_hash)
|
77
|
+
response = excon_request(url, req_hash)
|
78
|
+
rescue RestClient::Exception => ex
|
79
|
+
raise HttpError.new(ex)
|
80
|
+
end
|
81
|
+
response
|
82
|
+
end
|
83
|
+
|
84
|
+
def put(url, req_hash={})
|
85
|
+
response = nil
|
86
|
+
begin
|
87
|
+
req_hash[:method] = :put
|
88
|
+
req_hash[:url] = url
|
89
|
+
response = excon_request(url, req_hash)
|
90
|
+
rescue RestClient::Exception => ex
|
91
|
+
raise RestClientExceptionWrapper.new(ex)
|
92
|
+
end
|
93
|
+
response
|
94
|
+
end
|
95
|
+
|
96
|
+
def delete(url, req_hash={})
|
97
|
+
response = nil
|
98
|
+
begin
|
99
|
+
req_hash[:method] = :delete
|
100
|
+
req_hash[:url] = url
|
101
|
+
response = excon_request(url, req_hash)
|
102
|
+
rescue RestClient::Exception => ex
|
103
|
+
raise RestClientExceptionWrapper.new(ex)
|
104
|
+
end
|
105
|
+
response
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -10,7 +10,7 @@ module Rest
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
class NetHttpPersistentResponseWrapper
|
13
|
+
class NetHttpPersistentResponseWrapper < BaseResponseWrapper
|
14
14
|
def initialize(response)
|
15
15
|
@response = response
|
16
16
|
end
|
@@ -23,6 +23,10 @@ module Rest
|
|
23
23
|
@response.body
|
24
24
|
end
|
25
25
|
|
26
|
+
def headers_orig
|
27
|
+
@response.to_hash
|
28
|
+
end
|
29
|
+
|
26
30
|
end
|
27
31
|
|
28
32
|
class NetHttpPersistentWrapper < BaseWrapper
|
@@ -36,7 +40,7 @@ module Rest
|
|
36
40
|
|
37
41
|
def default_headers
|
38
42
|
{
|
39
|
-
"Accept-Encoding" => "gzip, deflate",
|
43
|
+
#"Accept-Encoding" => "gzip, deflate",
|
40
44
|
#"Accept" => "*/*; q=0.5, application/xml"
|
41
45
|
}
|
42
46
|
end
|
@@ -53,37 +57,49 @@ module Rest
|
|
53
57
|
def get(url, req_hash={}, options={})
|
54
58
|
@client.logger.debug "limit #{options[:limit]}"
|
55
59
|
options[:limit] ||= 10
|
56
|
-
|
60
|
+
r = nil
|
57
61
|
begin
|
58
62
|
|
59
63
|
uri = URI(url)
|
60
64
|
#p uri
|
61
65
|
#p uri.path
|
66
|
+
#p uri.request_uri
|
67
|
+
#puts "query: " + uri.query.inspect
|
68
|
+
#puts "fragment: " + uri.fragment.inspect
|
69
|
+
if req_hash[:params]
|
70
|
+
new_q = URI.encode_www_form(req_hash[:params])
|
71
|
+
if uri.query
|
72
|
+
new_q = uri.query + "&" + new_q
|
73
|
+
end
|
74
|
+
#puts "new_q: " + new_q
|
75
|
+
uri.query = new_q
|
76
|
+
end
|
77
|
+
#p uri.request_uri
|
62
78
|
post = Net::HTTP::Get.new fix_path(uri.request_uri)
|
63
79
|
add_headers(post, req_hash, default_headers)
|
64
80
|
response = http.request uri, post
|
65
81
|
@client.logger.debug response.class.name
|
82
|
+
r = NetHttpPersistentResponseWrapper.new(response)
|
66
83
|
case response
|
67
|
-
when Net::
|
68
|
-
|
69
|
-
response = get(response['location'], req_hash, {limit: options[:limit]-1})
|
70
|
-
when Net::HTTPMovedPermanently
|
71
|
-
@client.logger.debug "moved to #{response['location']}"
|
72
|
-
response = get(response['location'], req_hash, {limit: options[:limit]-1})
|
73
|
-
end
|
74
|
-
response = NetHttpPersistentResponseWrapper.new(response)
|
75
|
-
rescue Net::HTTPClientError => ex
|
76
|
-
if ex.code == 404
|
77
|
-
return NetHttpPersistentResponseWrapper.new(ex)
|
78
|
-
end
|
79
|
-
raise NetHttpPersistentExceptionWrapper.new(ex)
|
80
|
-
rescue Net::HTTPServerError => ex
|
81
|
-
if ex.code == 404
|
82
|
-
return NetHttpPersistentResponseWrapper.new(ex)
|
84
|
+
when Net::HTTPClientError, Net::HTTPServerError
|
85
|
+
raise Rest::HttpError.new(r)
|
83
86
|
end
|
84
|
-
|
87
|
+
# when Net::HTTPRedirection
|
88
|
+
# @client.logger.debug "moved to #{response['location']}"
|
89
|
+
# response = get(response['location'], req_hash, {limit: options[:limit]-1})
|
90
|
+
# when Net::HTTPMovedPermanently
|
91
|
+
# @client.logger.debug "moved to #{response['location']}"
|
92
|
+
# response = get(response['location'], req_hash, {limit: options[:limit]-1})
|
93
|
+
#end
|
94
|
+
#rescue Net::HTTPClientError, Net::HTTPServerError => ex
|
95
|
+
# raise NetHttpPersistentExceptionWrapper.new(ex)
|
96
|
+
#rescue Net::HTTPServerError => ex
|
97
|
+
# if ex.code == 404
|
98
|
+
# return NetHttpPersistentResponseWrapper.new(ex)
|
99
|
+
# end
|
100
|
+
# raise NetHttpPersistentExceptionWrapper.new(ex)
|
85
101
|
end
|
86
|
-
|
102
|
+
r
|
87
103
|
end
|
88
104
|
|
89
105
|
def fix_path(path)
|
@@ -3,14 +3,16 @@ require 'rest_client'
|
|
3
3
|
module Rest
|
4
4
|
|
5
5
|
module Wrappers
|
6
|
-
class RestClientExceptionWrapper <
|
6
|
+
class RestClientExceptionWrapper < HttpError
|
7
|
+
attr_reader :ex
|
8
|
+
|
7
9
|
def initialize(ex)
|
8
|
-
super(ex.
|
10
|
+
super(ex.response)
|
9
11
|
@ex = ex
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
|
-
class RestClientResponseWrapper
|
15
|
+
class RestClientResponseWrapper < BaseResponseWrapper
|
14
16
|
def initialize(response)
|
15
17
|
@response = response
|
16
18
|
end
|
@@ -23,6 +25,10 @@ module Rest
|
|
23
25
|
@response.body
|
24
26
|
end
|
25
27
|
|
28
|
+
def headers_orig
|
29
|
+
@response.headers
|
30
|
+
end
|
31
|
+
|
26
32
|
end
|
27
33
|
|
28
34
|
class RestClientWrapper < BaseWrapper
|
@@ -43,9 +49,9 @@ module Rest
|
|
43
49
|
response = RestClientResponseWrapper.new(r2)
|
44
50
|
rescue RestClient::Exception => ex
|
45
51
|
#p ex
|
46
|
-
if ex.http_code == 404
|
47
|
-
|
48
|
-
end
|
52
|
+
#if ex.http_code == 404
|
53
|
+
# return RestClientResponseWrapper.new(ex.response)
|
54
|
+
#end
|
49
55
|
raise RestClientExceptionWrapper.new(ex)
|
50
56
|
end
|
51
57
|
response
|
@@ -11,6 +11,26 @@ module Rest
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
class TyphoeusResponseWrapper < BaseResponseWrapper
|
15
|
+
|
16
|
+
def initialize(response)
|
17
|
+
@response = response
|
18
|
+
end
|
19
|
+
|
20
|
+
def code
|
21
|
+
@response.code
|
22
|
+
end
|
23
|
+
|
24
|
+
def body
|
25
|
+
@response.body
|
26
|
+
end
|
27
|
+
|
28
|
+
def headers_orig
|
29
|
+
@response.headers_hash
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
14
34
|
class TyphoeusWrapper < BaseWrapper
|
15
35
|
|
16
36
|
def default_typhoeus_options
|
@@ -28,29 +48,28 @@ module Rest
|
|
28
48
|
# puts "REQ_HASH=" + req_hash.inspect
|
29
49
|
response = Typhoeus::Request.get(url, req_hash)
|
30
50
|
#p response
|
51
|
+
response = handle_response(response)
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
def handle_response(response)
|
31
56
|
if response.timed_out?
|
32
57
|
raise TyphoeusTimeoutError.new(response)
|
33
58
|
end
|
34
|
-
|
35
|
-
response
|
59
|
+
r = TyphoeusResponseWrapper.new(response)
|
60
|
+
if response.code >= 400
|
61
|
+
raise Rest::HttpError.new(r)
|
62
|
+
end
|
63
|
+
r
|
36
64
|
end
|
37
65
|
|
38
|
-
|
39
|
-
def to_json_parts(h)
|
40
|
-
h[:body] = h[:body].to_json if h[:body] && h[:body].is_a?(Hash)
|
41
|
-
end
|
66
|
+
|
42
67
|
|
43
68
|
def post(url, req_hash={})
|
44
69
|
req_hash = default_typhoeus_options.merge(req_hash)
|
45
|
-
# puts "REQ_HASH=" + req_hash.inspect
|
46
|
-
|
47
|
-
# Convert body to json - NEED TO TEST THIS MORE
|
48
70
|
to_json_parts(req_hash)
|
49
71
|
response = Typhoeus::Request.post(url, req_hash)
|
50
|
-
|
51
|
-
if response.timed_out?
|
52
|
-
raise TyphoeusTimeoutError.new(response)
|
53
|
-
end
|
72
|
+
response = handle_response(response)
|
54
73
|
response
|
55
74
|
end
|
56
75
|
|
@@ -58,19 +77,14 @@ module Rest
|
|
58
77
|
req_hash = default_typhoeus_options.merge(req_hash)
|
59
78
|
# puts "REQ_HASH=" + req_hash.inspect
|
60
79
|
response = Typhoeus::Request.put(url, req_hash)
|
61
|
-
|
62
|
-
if response.timed_out?
|
63
|
-
raise TyphoeusTimeoutError.new(response)
|
64
|
-
end
|
80
|
+
response = handle_response(response)
|
65
81
|
response
|
66
82
|
end
|
67
83
|
|
68
84
|
def delete(url, req_hash={})
|
69
85
|
req_hash = default_typhoeus_options.merge(req_hash)
|
70
86
|
response = Typhoeus::Request.delete(url, req_hash)
|
71
|
-
|
72
|
-
raise TyphoeusTimeoutError.new(response)
|
73
|
-
end
|
87
|
+
response = handle_response(response)
|
74
88
|
response
|
75
89
|
end
|
76
90
|
|
data/rest.gemspec
CHANGED
@@ -17,13 +17,15 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.required_rubygems_version = ">= 1.3.6"
|
18
18
|
gem.required_ruby_version = Gem::Requirement.new(">= 1.9")
|
19
19
|
gem.add_runtime_dependency "rest-client", ">= 0.3.0"
|
20
|
+
gem.add_runtime_dependency "net-http-persistent"
|
20
21
|
|
21
22
|
gem.add_development_dependency "test-unit"
|
23
|
+
gem.add_development_dependency "minitest"
|
22
24
|
gem.add_development_dependency "rake"
|
23
25
|
gem.add_development_dependency "uber_config"
|
24
26
|
gem.add_development_dependency "typhoeus"
|
25
27
|
gem.add_development_dependency "quicky"
|
26
|
-
gem.add_development_dependency "
|
28
|
+
gem.add_development_dependency "excon"
|
27
29
|
|
28
30
|
end
|
29
31
|
|
data/test/test_base.rb
CHANGED
@@ -8,13 +8,18 @@ rescue Exception => ex
|
|
8
8
|
raise ex
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
11
|
class TestBase < Test::Unit::TestCase
|
13
|
-
|
12
|
+
|
13
|
+
def setup
|
14
14
|
puts 'setup'
|
15
|
-
|
16
|
-
@rest = Rest::Client.new(:gem=>:rest_client)
|
15
|
+
@rest = Rest::Client.new(:gem => :net_http_persistent)
|
17
16
|
@rest.logger.level = Logger::DEBUG
|
17
|
+
@request_bin = "http://requestb.in/13t6hs51"
|
18
18
|
|
19
19
|
end
|
20
|
+
|
21
|
+
def bin
|
22
|
+
@request_bin
|
23
|
+
end
|
24
|
+
|
20
25
|
end
|
data/test/test_performance.rb
CHANGED
@@ -5,19 +5,20 @@ require 'quicky'
|
|
5
5
|
|
6
6
|
require_relative 'test_base'
|
7
7
|
|
8
|
-
class
|
8
|
+
class TestPerformance < TestBase
|
9
9
|
def setup
|
10
10
|
super
|
11
11
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_get_performance
|
15
|
+
puts 'test_get_performance'
|
15
16
|
|
16
|
-
times =
|
17
|
+
times = 100
|
17
18
|
|
18
19
|
quicky = Quicky::Timer.new
|
19
20
|
|
20
|
-
to_run = [:typhoeus, :rest_client, :net_http_persistent]
|
21
|
+
to_run = [:typhoeus, :rest_client, :net_http_persistent, :excon]
|
21
22
|
to_run.each do |gem|
|
22
23
|
run_perf(quicky, times, gem)
|
23
24
|
end
|
@@ -32,7 +33,7 @@ class TestTests < TestBase
|
|
32
33
|
puts "Starting #{gem} test..."
|
33
34
|
client = Rest::Client.new(:gem => gem)
|
34
35
|
quicky.loop(gem, times) do
|
35
|
-
client.get("http://
|
36
|
+
client.get("http://rest-test.iron.io/code/200")
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
data/test/test_rest.rb
CHANGED
@@ -5,7 +5,7 @@ require 'test/unit'
|
|
5
5
|
require 'yaml'
|
6
6
|
require_relative 'test_base'
|
7
7
|
|
8
|
-
class
|
8
|
+
class TestRest < TestBase
|
9
9
|
def setup
|
10
10
|
super
|
11
11
|
|
@@ -17,7 +17,7 @@ class TestTests < TestBase
|
|
17
17
|
p response
|
18
18
|
p response.code
|
19
19
|
assert response.code == 200
|
20
|
-
|
20
|
+
p response.body
|
21
21
|
assert response.body.include?("Social Coding")
|
22
22
|
end
|
23
23
|
|
@@ -25,6 +25,9 @@ class TestTests < TestBase
|
|
25
25
|
response = @rest.get("http://rest-test.iron.io/code/503?switch_after=3&switch_to=200")
|
26
26
|
p response
|
27
27
|
p response.code
|
28
|
+
p response.tries == 3
|
29
|
+
assert response.code == 200
|
30
|
+
|
28
31
|
end
|
29
32
|
|
30
33
|
def test_gets
|
@@ -35,8 +38,64 @@ class TestTests < TestBase
|
|
35
38
|
'User-Agent' => "someagent"
|
36
39
|
}
|
37
40
|
body = {"foo" => "bar"}
|
38
|
-
response = @rest.get("
|
41
|
+
response = @rest.get("#{bin}?param1=x")
|
42
|
+
|
43
|
+
# params as hash
|
44
|
+
response = @rest.get("#{bin}?x=y#frag", :params => {:param2 => "abc"})
|
45
|
+
response = @rest.get("#{bin}", :params => {param3: "xyz"})
|
46
|
+
response = @rest.get("#{bin}")
|
47
|
+
|
48
|
+
response = @rest.get("http://rest-test.iron.io/code/200")
|
49
|
+
assert response.code == 200
|
50
|
+
assert response.body.include?("200")
|
51
|
+
p response.headers
|
52
|
+
assert response.headers.is_a?(Hash)
|
53
|
+
|
54
|
+
end
|
39
55
|
|
56
|
+
def test_404
|
57
|
+
begin
|
58
|
+
response = @rest.get("http://rest-test.iron.io/code/404")
|
59
|
+
assert false, "shouldn't get here"
|
60
|
+
rescue Rest::HttpError => ex
|
61
|
+
puts "EX: " + ex.inspect
|
62
|
+
p ex.backtrace
|
63
|
+
assert ex.is_a?(Rest::HttpError)
|
64
|
+
assert ex.response
|
65
|
+
assert ex.response.body
|
66
|
+
assert ex.code == 404
|
67
|
+
assert ex.response.body.include?("404")
|
68
|
+
assert ex.to_s.include?("404")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_400
|
73
|
+
begin
|
74
|
+
response = @rest.get("http://rest-test.iron.io/code/400")
|
75
|
+
assert false, "shouldn't get here"
|
76
|
+
rescue Rest::HttpError => ex
|
77
|
+
puts "EX: #{ex}"
|
78
|
+
p ex.backtrace
|
79
|
+
assert ex.is_a?(Rest::HttpError)
|
80
|
+
assert ex.response
|
81
|
+
assert ex.response.body
|
82
|
+
assert ex.code == 400
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_500
|
87
|
+
puts '500'
|
88
|
+
begin
|
89
|
+
response = @rest.get("http://rest-test.iron.io/code/500")
|
90
|
+
assert false, "shouldn't get here"
|
91
|
+
rescue Rest::HttpError => ex
|
92
|
+
puts "EX: " + ex.inspect
|
93
|
+
p ex.backtrace
|
94
|
+
assert ex.is_a?(Rest::HttpError)
|
95
|
+
assert ex.response
|
96
|
+
assert ex.response.body
|
97
|
+
assert ex.code == 500
|
98
|
+
end
|
40
99
|
end
|
41
100
|
|
42
101
|
def test_post_with_headers
|
@@ -48,12 +107,16 @@ class TestTests < TestBase
|
|
48
107
|
'User-Agent' => "someagent"
|
49
108
|
}
|
50
109
|
body = {"foo" => "bar"}
|
51
|
-
response = @rest.post("
|
110
|
+
response = @rest.post("#{bin}",
|
111
|
+
:body => body,
|
112
|
+
:headers => headers)
|
113
|
+
p response
|
114
|
+
response = @rest.post("http://rest-test.iron.io/code/200",
|
52
115
|
:body => body,
|
53
116
|
:headers => headers)
|
54
117
|
p response
|
55
118
|
|
56
|
-
response = @rest.post("
|
119
|
+
response = @rest.post("#{bin}",
|
57
120
|
:body => "some string body",
|
58
121
|
:headers => headers)
|
59
122
|
p response
|
data/test/tmp.rb
CHANGED
@@ -1,14 +1,27 @@
|
|
1
|
+
gem 'test-unit'
|
2
|
+
require 'test/unit'
|
1
3
|
require 'yaml'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
4
|
+
require_relative 'test_base'
|
5
|
+
|
6
|
+
class TestTemp < TestBase
|
7
|
+
def setup
|
8
|
+
super
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_500
|
13
|
+
puts '500'
|
14
|
+
begin
|
15
|
+
puts 'in block'
|
16
|
+
response = @rest.get("http://rest-test.iron.io/code/500")
|
17
|
+
assert false, "shouldn't get here"
|
18
|
+
rescue => ex
|
19
|
+
p ex
|
20
|
+
assert ex.is_a?(Rest::HttpError)
|
21
|
+
assert ex.response
|
22
|
+
assert ex.response.body
|
23
|
+
assert ex.code == 500
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
11
27
|
|
12
|
-
response = @rest.get("http://smooth-sword-1395.herokuapp.com/code/503?switch_after=3&switch_to=200")
|
13
|
-
p response
|
14
|
-
p response.code
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 0.3.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-http-persistent
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: test-unit
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -43,6 +59,22 @@ dependencies:
|
|
43
59
|
- - ! '>='
|
44
60
|
- !ruby/object:Gem::Version
|
45
61
|
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
46
78
|
- !ruby/object:Gem::Dependency
|
47
79
|
name: rake
|
48
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +140,7 @@ dependencies:
|
|
108
140
|
- !ruby/object:Gem::Version
|
109
141
|
version: '0'
|
110
142
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
143
|
+
name: excon
|
112
144
|
requirement: !ruby/object:Gem::Requirement
|
113
145
|
none: false
|
114
146
|
requirements:
|
@@ -138,8 +170,10 @@ files:
|
|
138
170
|
- Rakefile
|
139
171
|
- lib/rest.rb
|
140
172
|
- lib/rest/client.rb
|
173
|
+
- lib/rest/errors.rb
|
141
174
|
- lib/rest/version.rb
|
142
175
|
- lib/rest/wrappers/base_wrapper.rb
|
176
|
+
- lib/rest/wrappers/excon_wrapper.rb
|
143
177
|
- lib/rest/wrappers/net_http_persistent_wrapper.rb
|
144
178
|
- lib/rest/wrappers/rest_client_wrapper.rb
|
145
179
|
- lib/rest/wrappers/typhoeus_wrapper.rb
|