saddle 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/saddle/middleware/logging/airbrake.rb +35 -0
- data/lib/saddle/middleware/logging/statsd.rb +49 -0
- data/lib/saddle/middleware/request/encode_json.rb +34 -0
- data/lib/saddle/middleware/request/retry.rb +55 -0
- data/lib/saddle/middleware/request/url_encoded.rb +86 -0
- data/lib/saddle/middleware/response/default_response.rb +24 -0
- data/lib/saddle/middleware/response/parse_json.rb +45 -0
- data/lib/saddle/options.rb +11 -17
- data/lib/saddle/requester.rb +34 -40
- data/lib/saddle/version.rb +1 -1
- data/spec/requester/get_spec.rb +40 -0
- data/spec/requester/post_spec.rb +56 -0
- data/spec/requester/retry_spec.rb +54 -0
- metadata +15 -8
- data/lib/saddle/middleware/airbrake_logging.rb +0 -31
- data/lib/saddle/middleware/default_response.rb +0 -24
- data/lib/saddle/middleware/parse_json.rb +0 -36
- data/lib/saddle/middleware/statsd_logging.rb +0 -45
- data/spec/saddle_client_spec.rb +0 -34
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NDdlNWQ0MWNlODhhYTQ2NTMwZWQ2MDhkMjRlOGQ1YTQ1MTBhMjNjMA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YmE2MmYxZjQyNjhmYTJhNzhkZjk3MDcwMjdhNjgxNTI5ZWJlZDAyZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MWQ4Y2ZiOThmMGIwNjNiMDQ5M2EwMTNkZjdkMmIyMjFhOGFiNmU3NTNjMjQy
|
10
|
+
NGI4MmQyNWNmOTY5M2Y5MjJmMTg5ZGRjMThjYWUwZTRlZWQ3MDhkZDdiODIw
|
11
|
+
NWQwMWM4YTZmNjVmNmZjZjc3NjIwZDlhMGRlMDYzOWM3M2Y0ZTQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODM4ZGM4ZTdlYTM3OGY3NzNkYTZlOTQ3ZWY0N2Y2MzViZjgzZWFiZjA2Njg4
|
14
|
+
Mjc4Y2NiNGVkYmZiZDhjYTliMzZmYmE0NjhkNDQ3YmY4MTQ0NjIzMzk0ZTkx
|
15
|
+
ZTczYmRkYTViOWIzODY0NWI0MGY3YWVmNDIzMDYxYTE2MDIwMmU=
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'airbrake'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Saddle::Middleware
|
7
|
+
module Logging
|
8
|
+
|
9
|
+
# Public: Reports exceptions to Airbrake
|
10
|
+
#
|
11
|
+
class AirbrakeLogger < Faraday::Middleware
|
12
|
+
|
13
|
+
def initialize(app, airbrake_api_key=nil)
|
14
|
+
super(app)
|
15
|
+
@airbrake_api_key = airbrake_api_key
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
begin
|
20
|
+
@app.call(env)
|
21
|
+
rescue => e
|
22
|
+
# If we don't have an api key, use the default config
|
23
|
+
if @airbrake_api_key
|
24
|
+
::Airbrake.notify(e, {:api_key => @airbrake_api_key} )
|
25
|
+
else
|
26
|
+
::Airbrake.notify(e)
|
27
|
+
end
|
28
|
+
# Re-raise the error
|
29
|
+
raise
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'statsd'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
module Saddle::Middleware
|
8
|
+
module Logging
|
9
|
+
|
10
|
+
# Public: Wraps request with statsd logging
|
11
|
+
# Expects statsd_path in request options. However, if using saddle and no statsd_path is specified
|
12
|
+
# will read call_chain and action and use them to construct a statsd_path
|
13
|
+
class StatsdLogger < Faraday::Middleware
|
14
|
+
attr_accessor :graphite_host, :graphite_port, :namespace
|
15
|
+
|
16
|
+
def initialize(app, graphite_host, graphite_port=nil, namespace=nil)
|
17
|
+
super(app)
|
18
|
+
@graphite_host = graphite_host
|
19
|
+
@graphite_port = graphite_port
|
20
|
+
@namespace = namespace
|
21
|
+
end
|
22
|
+
|
23
|
+
def statsd
|
24
|
+
@statsd ||= begin
|
25
|
+
client = ::Statsd.new(@graphite_host, @graphite_port)
|
26
|
+
client.namespace = @namespace if @namespace
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
statsd_path = nil
|
32
|
+
if env[:request][:statsd_path]
|
33
|
+
statsd_path = env[:request][:statsd_path]
|
34
|
+
elsif env[:request][:saddle] && env[:request][:saddle][:call_chain] && env[:request][:saddle][:action]
|
35
|
+
statsd_path = (env[:request][:saddle][:call_chain] + [env[:request][:saddle][:action]]).join('.')
|
36
|
+
end
|
37
|
+
|
38
|
+
if statsd_path
|
39
|
+
self.statsd.time statsd_path do
|
40
|
+
@app.call(env)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@app.call(env)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Saddle::Middleware
|
6
|
+
module Request
|
7
|
+
|
8
|
+
# Request middleware that encodes the body as JSON.
|
9
|
+
#
|
10
|
+
# Make sure you set request[:request_style] = :json
|
11
|
+
# for it to be activated.
|
12
|
+
|
13
|
+
class JsonEncoded < Faraday::Middleware
|
14
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
15
|
+
MIME_TYPE = 'application/json'.freeze
|
16
|
+
|
17
|
+
dependency do
|
18
|
+
require 'json' unless defined?(::JSON)
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
if env[:request][:request_style] == :json
|
23
|
+
# Make sure we're working with a valid body that's not a String
|
24
|
+
if env[:body] and !env[:body].respond_to?(:to_str)
|
25
|
+
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
26
|
+
env[:body] = ::JSON.dump(env[:body])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@app.call env
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Saddle::Middleware
|
6
|
+
module Request
|
7
|
+
|
8
|
+
# Catches exceptions and retries each request a limited number of times.
|
9
|
+
#
|
10
|
+
# By default, it retries 2 times and performs exponential backoff, starting
|
11
|
+
# at 50ms
|
12
|
+
class Retry < Faraday::Middleware
|
13
|
+
def initialize(app, ignored_exceptions=[])
|
14
|
+
super(app)
|
15
|
+
@ignored_exceptions = ignored_exceptions
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
retries = env[:request][:num_retries] || 2
|
20
|
+
backoff = env[:request][:retry_backoff] || 0.050 # ms
|
21
|
+
begin
|
22
|
+
@app.call(self.class.deep_copy(env))
|
23
|
+
rescue => e
|
24
|
+
unless @ignored_exceptions.include?(e.class)
|
25
|
+
# Retry a limited number of times
|
26
|
+
if retries > 0
|
27
|
+
retries -= 1
|
28
|
+
sleep(backoff) if backoff > 0.0
|
29
|
+
backoff *= 2
|
30
|
+
retry
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# Re-raise if we're out of retries or it's not handled
|
34
|
+
raise
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.deep_copy(value)
|
39
|
+
if value.is_a?(Hash)
|
40
|
+
result = value.clone
|
41
|
+
value.each{|k, v| result[k] = deep_copy(v)}
|
42
|
+
result
|
43
|
+
elsif value.is_a?(Array)
|
44
|
+
result = value.clone
|
45
|
+
result.clear
|
46
|
+
value.each{|v| result << deep_copy(v)}
|
47
|
+
result
|
48
|
+
else
|
49
|
+
value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Saddle::Middleware
|
6
|
+
module Request
|
7
|
+
|
8
|
+
# This magically handles converting your body from a hash
|
9
|
+
# into an url-encoded (or multipart if needed) request
|
10
|
+
|
11
|
+
# Make sure you set request[:request_style] = :urlencoded
|
12
|
+
# for it to be activated.
|
13
|
+
|
14
|
+
class UrlEncoded < Faraday::Middleware
|
15
|
+
CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
|
16
|
+
|
17
|
+
URL_ENCODED_MIME_TYPE = 'application/x-www-form-urlencoded'.freeze
|
18
|
+
MULTIPART_MIME_TYPE = 'multipart/form-data'.freeze
|
19
|
+
|
20
|
+
VALID_MIME_TYPES = [URL_ENCODED_MIME_TYPE, MULTIPART_MIME_TYPE]
|
21
|
+
|
22
|
+
DEFAULT_MULTIPART_BOUNDARY = "-^---_---^-".freeze
|
23
|
+
|
24
|
+
|
25
|
+
def call(env)
|
26
|
+
if env[:request][:request_style] == :urlencoded
|
27
|
+
# Make sure we're working with a valid body that's not a String
|
28
|
+
if env[:body] and !env[:body].respond_to?(:to_str)
|
29
|
+
if has_multipart?(env[:body])
|
30
|
+
env[:request][:boundary] ||= DEFAULT_MULTIPART_BOUNDARY
|
31
|
+
env[:request_headers][CONTENT_TYPE] ||= MULTIPART_MIME_TYPE
|
32
|
+
env[:request_headers][CONTENT_TYPE] += ";boundary=#{env[:request][:boundary]}"
|
33
|
+
env[:body] = create_multipart(env, env[:body])
|
34
|
+
else
|
35
|
+
env[:request_headers][CONTENT_TYPE] ||= URL_ENCODED_MIME_TYPE
|
36
|
+
env[:body] = Faraday::Utils::ParamsHash[env[:body]].to_query
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
@app.call env
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def has_multipart?(obj)
|
47
|
+
# string is an enum in 1.8, returning list of itself
|
48
|
+
if obj.respond_to?(:each) && !obj.is_a?(String)
|
49
|
+
(obj.respond_to?(:values) ? obj.values : obj).each do |val|
|
50
|
+
return true if (val.respond_to?(:content_type) || has_multipart?(val))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_multipart(env, params)
|
57
|
+
boundary = env[:request][:boundary]
|
58
|
+
parts = process_params(params) do |key, value|
|
59
|
+
Faraday::Parts::Part.new(boundary, key, value)
|
60
|
+
end
|
61
|
+
parts << Faraday::Parts::EpiloguePart.new(boundary)
|
62
|
+
|
63
|
+
body = Faraday::CompositeReadIO.new(parts)
|
64
|
+
env[:request_headers][Faraday::Env::ContentLength] = body.length.to_s
|
65
|
+
body
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_params(params, prefix = nil, pieces = nil, &block)
|
69
|
+
params.inject(pieces || []) do |all, (key, value)|
|
70
|
+
key = "#{prefix}[#{key}]" if prefix
|
71
|
+
|
72
|
+
case value
|
73
|
+
when Array
|
74
|
+
values = value.inject([]) { |a,v| a << [nil, v] }
|
75
|
+
process_params(values, key, all, &block)
|
76
|
+
when Hash
|
77
|
+
process_params(value, key, all, &block)
|
78
|
+
else
|
79
|
+
all << block.call(key, value)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
|
4
|
+
module Saddle::Middleware
|
5
|
+
module Response
|
6
|
+
|
7
|
+
# Public: Returns a default response in the case of an exception
|
8
|
+
# Expects default_response to be defined in the request of connection options, otherwise rethrows exception
|
9
|
+
class DefaultResponse < Faraday::Middleware
|
10
|
+
def call(env)
|
11
|
+
begin
|
12
|
+
@app.call(env)
|
13
|
+
rescue Faraday::Error
|
14
|
+
if res = env[:request][:default_response]
|
15
|
+
return ::Faraday::Response.new(:body => res)
|
16
|
+
else
|
17
|
+
raise
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Saddle::Middleware
|
6
|
+
module Response
|
7
|
+
|
8
|
+
# Public: Parse response bodies as JSON.
|
9
|
+
class ParseJson < Faraday::Middleware
|
10
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
11
|
+
MIME_TYPE = 'application/json'.freeze
|
12
|
+
|
13
|
+
dependency do
|
14
|
+
require 'json' unless defined?(::JSON)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
if parse_response?(env)
|
19
|
+
# Make sure we're working with a valid body that's not a String
|
20
|
+
if env.body and !env.body.respond_to?(:to_str)
|
21
|
+
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
22
|
+
env.body = ::JSON.dump env.body
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@app.call env
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_response?(env)
|
29
|
+
has_body?(env) and (response_type(env) == MIME_TYPE)
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_body?(env)
|
33
|
+
body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
|
34
|
+
end
|
35
|
+
|
36
|
+
def response_type(env)
|
37
|
+
return nil unless env[:response_headers]
|
38
|
+
type = env[:response_headers][CONTENT_TYPE].to_s
|
39
|
+
type = type.split(';', 2).first if type.index(';')
|
40
|
+
type
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/saddle/options.rb
CHANGED
@@ -13,11 +13,10 @@ module Saddle::Options
|
|
13
13
|
:host => host,
|
14
14
|
:port => port,
|
15
15
|
:use_ssl => use_ssl,
|
16
|
-
:
|
17
|
-
:response_style => response_style,
|
16
|
+
:request_style => request_style,
|
18
17
|
:num_retries => num_retries,
|
19
18
|
:timeout => timeout,
|
20
|
-
:additional_middlewares => additional_middlewares,
|
19
|
+
:additional_middlewares => @@additional_middlewares,
|
21
20
|
:stubs => stubs,
|
22
21
|
}
|
23
22
|
end
|
@@ -39,13 +38,7 @@ module Saddle::Options
|
|
39
38
|
|
40
39
|
# The POST/PUT style for this client
|
41
40
|
# options are [:json, :urlencoded]
|
42
|
-
def
|
43
|
-
:json
|
44
|
-
end
|
45
|
-
|
46
|
-
# How to parse results
|
47
|
-
# options are [:json, :urlencoded]
|
48
|
-
def response_style
|
41
|
+
def request_style
|
49
42
|
:json
|
50
43
|
end
|
51
44
|
|
@@ -59,17 +52,18 @@ module Saddle::Options
|
|
59
52
|
30
|
60
53
|
end
|
61
54
|
|
62
|
-
#
|
55
|
+
# Use this to add additional middleware to the request stack
|
63
56
|
# ex:
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
57
|
+
# add_middleware({
|
58
|
+
# :klass => MyMiddleware,
|
59
|
+
# :args => [arg1, arg2],
|
60
|
+
# })
|
68
61
|
# end
|
69
62
|
#
|
70
63
|
###
|
71
|
-
|
72
|
-
|
64
|
+
@@additional_middlewares = []
|
65
|
+
def add_middleware m
|
66
|
+
@@additional_middlewares << m
|
73
67
|
end
|
74
68
|
|
75
69
|
# If the Typhoeus adapter is being used, pass stubs to it for testing.
|
data/lib/saddle/requester.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
require 'faraday_middleware'
|
3
3
|
|
4
|
-
require 'saddle/middleware/
|
5
|
-
require 'saddle/middleware/
|
4
|
+
require 'saddle/middleware/request/encode_json'
|
5
|
+
require 'saddle/middleware/request/retry'
|
6
|
+
require 'saddle/middleware/request/url_encoded'
|
7
|
+
require 'saddle/middleware/response/default_response'
|
8
|
+
require 'saddle/middleware/response/parse_json'
|
6
9
|
require 'saddle/middleware/ruby_timeout'
|
7
10
|
|
8
11
|
|
@@ -21,8 +24,7 @@ module Saddle
|
|
21
24
|
## host - host to connect to (default: localhost)
|
22
25
|
## port - port to connect on (default: 80)
|
23
26
|
## use_ssl - true if we should use https (default: false)
|
24
|
-
##
|
25
|
-
## response_style - :json or :urlencoded (default: :json)
|
27
|
+
## request_style - :json or :urlencoded (default: :json)
|
26
28
|
## num_retries - number of times to retry each request (default: 3)
|
27
29
|
## timeout - timeout in seconds
|
28
30
|
## additional_middleware - an Array of more middlewares to apply to the top of the stack
|
@@ -35,10 +37,8 @@ module Saddle
|
|
35
37
|
raise ':port must be an integer' unless @port.is_a?(Fixnum)
|
36
38
|
@use_ssl = opt[:use_ssl] || false
|
37
39
|
raise ':use_ssl must be true or false' unless (@use_ssl.is_a?(TrueClass) || @use_ssl.is_a?(FalseClass))
|
38
|
-
@
|
39
|
-
raise ":
|
40
|
-
@response_style = opt[:response_style] || :json
|
41
|
-
raise ":response_style must be in: #{VALID_BODY_STYLES.join(',')}" unless VALID_BODY_STYLES.include?(@response_style)
|
40
|
+
@request_style = opt[:request_style] || :json
|
41
|
+
raise ":request_style must be in: #{VALID_BODY_STYLES.join(',')}" unless VALID_BODY_STYLES.include?(@request_style)
|
42
42
|
@num_retries = opt[:num_retries] || 3
|
43
43
|
raise ':num_retries must be an integer' unless @num_retries.is_a?(Fixnum)
|
44
44
|
@timeout = opt[:timeout]
|
@@ -65,33 +65,24 @@ module Saddle
|
|
65
65
|
response.body
|
66
66
|
end
|
67
67
|
|
68
|
-
#
|
69
|
-
def
|
70
|
-
response = connection.
|
68
|
+
# Make a POST request
|
69
|
+
def post(url, data={}, options={})
|
70
|
+
response = connection.post do |req|
|
71
71
|
req.options.merge! options
|
72
72
|
req.url url
|
73
|
-
|
74
|
-
case @post_style
|
75
|
-
when :json
|
76
|
-
req.headers['Content-Type'] = 'application/json'
|
77
|
-
req.body = params.to_json
|
78
|
-
when :urlencoded
|
79
|
-
req.params = params
|
80
|
-
else
|
81
|
-
raise RuntimeError(":post_style must be one of: #{VALID_POST_STYLES.join(',')}")
|
82
|
-
end
|
73
|
+
req.body = data
|
83
74
|
end
|
84
75
|
response.body
|
85
76
|
end
|
86
77
|
|
87
|
-
# Make a POST request
|
88
|
-
def post(url, params={}, options={})
|
89
|
-
post_or_put(:post, url, params, options)
|
90
|
-
end
|
91
|
-
|
92
78
|
# Make a PUT request
|
93
|
-
def put(url,
|
94
|
-
|
79
|
+
def put(url, data={}, options={})
|
80
|
+
response = connection.put do |req|
|
81
|
+
req.options.merge! options
|
82
|
+
req.url url
|
83
|
+
req.body = data
|
84
|
+
end
|
85
|
+
response.body
|
95
86
|
end
|
96
87
|
|
97
88
|
# Make a DELETE request
|
@@ -118,10 +109,12 @@ module Saddle
|
|
118
109
|
# Config options
|
119
110
|
unless @timeout.nil?
|
120
111
|
builder.options[:timeout] = @timeout
|
112
|
+
builder.options[:request_style] = @request_style
|
113
|
+
builder.options[:num_retries] = @num_retries
|
121
114
|
end
|
122
115
|
|
123
116
|
# Support default return values upon exception
|
124
|
-
builder.use Saddle::Middleware::DefaultResponse
|
117
|
+
builder.use Saddle::Middleware::Response::DefaultResponse
|
125
118
|
|
126
119
|
# Apply additional implementation-specific middlewares
|
127
120
|
@additional_middlewares.each do |m|
|
@@ -131,12 +124,18 @@ module Saddle
|
|
131
124
|
# Hard timeout on the entire request
|
132
125
|
builder.use Saddle::Middleware::RubyTimeout
|
133
126
|
|
134
|
-
#
|
135
|
-
builder.
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
127
|
+
# Request encoding
|
128
|
+
builder.use Saddle::Middleware::Request::JsonEncoded
|
129
|
+
builder.use Saddle::Middleware::Request::UrlEncoded
|
130
|
+
|
131
|
+
# Automatic retries
|
132
|
+
builder.use Saddle::Middleware::Request::Retry
|
133
|
+
|
134
|
+
# Handle parsing out the response if it's JSON
|
135
|
+
builder.use Saddle::Middleware::Response::ParseJson
|
136
|
+
|
137
|
+
# Raise exceptions on 4xx and 5xx errors
|
138
|
+
builder.use Faraday::Response::RaiseError
|
140
139
|
|
141
140
|
# Set up our adapter
|
142
141
|
if @stubs.nil?
|
@@ -146,11 +145,6 @@ module Saddle
|
|
146
145
|
# Use the test adapter
|
147
146
|
builder.adapter :test, @stubs
|
148
147
|
end
|
149
|
-
|
150
|
-
# Raise exceptions on 4xx and 5xx errors
|
151
|
-
builder.response :raise_error
|
152
|
-
# Handle parsing out the response if it's JSON
|
153
|
-
builder.use Saddle::Middleware::ParseJson
|
154
148
|
end
|
155
149
|
end
|
156
150
|
|
data/lib/saddle/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'saddle'
|
2
|
+
|
3
|
+
describe Saddle::Client do
|
4
|
+
|
5
|
+
context "GET requests" do
|
6
|
+
context "using the default client" do
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@stubs = Faraday::Adapter::Test::Stubs.new
|
10
|
+
@default_client = Saddle::Client.create(:stubs => @stubs)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should request properly with params" do
|
14
|
+
@stubs.get('/test?name=mike&party=true') {
|
15
|
+
[
|
16
|
+
200,
|
17
|
+
{},
|
18
|
+
'Party on!',
|
19
|
+
]
|
20
|
+
}
|
21
|
+
@default_client.requester.get(
|
22
|
+
'/test',
|
23
|
+
{'name' => 'mike', 'party' => true}
|
24
|
+
).should == 'Party on!'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse JSON encoded responses" do
|
28
|
+
@stubs.get('/test.json') {
|
29
|
+
[
|
30
|
+
200,
|
31
|
+
{'Content-Type' => 'application/json'},
|
32
|
+
{'success' => true},
|
33
|
+
]
|
34
|
+
}
|
35
|
+
@default_client.requester.get('/test.json')['success'].should == true
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'saddle'
|
2
|
+
|
3
|
+
describe Saddle::Client do
|
4
|
+
|
5
|
+
context "POST requests" do
|
6
|
+
context "using the default client" do
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@stubs = Faraday::Adapter::Test::Stubs.new
|
10
|
+
@default_client = Saddle::Client.create(:stubs => @stubs)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should post empty" do
|
14
|
+
@stubs.post('/test') {
|
15
|
+
[
|
16
|
+
200,
|
17
|
+
{},
|
18
|
+
'Party on!',
|
19
|
+
]
|
20
|
+
}
|
21
|
+
@default_client.requester.post('/test').should == 'Party on!'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should post url encoded" do
|
25
|
+
@stubs.post('/test', 'a=0&b=true&c=Wingdings') {
|
26
|
+
[
|
27
|
+
200,
|
28
|
+
{},
|
29
|
+
'Party on!',
|
30
|
+
]
|
31
|
+
}
|
32
|
+
@default_client.requester.post(
|
33
|
+
'/test',
|
34
|
+
{'a' => 0, 'b' => true, 'c' => 'Wingdings'},
|
35
|
+
{:request_style => :urlencoded}
|
36
|
+
).should == 'Party on!'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should post JSON encoded" do
|
40
|
+
@stubs.post('/test', '{"a":0,"b":true,"c":"Wingdings"}') {
|
41
|
+
[
|
42
|
+
200,
|
43
|
+
{},
|
44
|
+
'Party on!',
|
45
|
+
]
|
46
|
+
}
|
47
|
+
@default_client.requester.post(
|
48
|
+
'/test',
|
49
|
+
{'a' => 0, 'b' => true, 'c' => 'Wingdings'},
|
50
|
+
{:request_style => :json}
|
51
|
+
).should == 'Party on!'
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'saddle'
|
2
|
+
|
3
|
+
describe Saddle::Client do
|
4
|
+
|
5
|
+
context "retry requests" do
|
6
|
+
context "using the default client" do
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@stubs = Faraday::Adapter::Test::Stubs.new
|
10
|
+
@default_client = Saddle::Client.create(:stubs => @stubs)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should retry properly with no params" do
|
14
|
+
@stubs.get('/test') {
|
15
|
+
[
|
16
|
+
500,
|
17
|
+
{},
|
18
|
+
'Failure',
|
19
|
+
]
|
20
|
+
}
|
21
|
+
@stubs.get('/test') {
|
22
|
+
[
|
23
|
+
200,
|
24
|
+
{},
|
25
|
+
'Party!',
|
26
|
+
]
|
27
|
+
}
|
28
|
+
@default_client.requester.get('/test').should == 'Party!'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should retry properly when posting params urlencoded" do
|
32
|
+
@stubs.post('/test', '{"a":"b","c":"d"}') {
|
33
|
+
[
|
34
|
+
500,
|
35
|
+
{},
|
36
|
+
'Failure',
|
37
|
+
]
|
38
|
+
}
|
39
|
+
@stubs.post('/test', '{"a":"b","c":"d"}') {
|
40
|
+
[
|
41
|
+
200,
|
42
|
+
{},
|
43
|
+
'Party!',
|
44
|
+
]
|
45
|
+
}
|
46
|
+
@default_client.requester.post(
|
47
|
+
'/test',
|
48
|
+
{'a' => 'b', 'c' => 'd'}
|
49
|
+
).should == 'Party!'
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saddle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Lewis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -68,16 +68,21 @@ files:
|
|
68
68
|
- lib/saddle.rb
|
69
69
|
- lib/saddle/endpoint.rb
|
70
70
|
- lib/saddle/method_tree_builder.rb
|
71
|
-
- lib/saddle/middleware/
|
72
|
-
- lib/saddle/middleware/
|
73
|
-
- lib/saddle/middleware/
|
71
|
+
- lib/saddle/middleware/logging/airbrake.rb
|
72
|
+
- lib/saddle/middleware/logging/statsd.rb
|
73
|
+
- lib/saddle/middleware/request/encode_json.rb
|
74
|
+
- lib/saddle/middleware/request/retry.rb
|
75
|
+
- lib/saddle/middleware/request/url_encoded.rb
|
76
|
+
- lib/saddle/middleware/response/default_response.rb
|
77
|
+
- lib/saddle/middleware/response/parse_json.rb
|
74
78
|
- lib/saddle/middleware/ruby_timeout.rb
|
75
|
-
- lib/saddle/middleware/statsd_logging.rb
|
76
79
|
- lib/saddle/options.rb
|
77
80
|
- lib/saddle/requester.rb
|
78
81
|
- lib/saddle/version.rb
|
79
82
|
- saddle.gemspec
|
80
|
-
- spec/
|
83
|
+
- spec/requester/get_spec.rb
|
84
|
+
- spec/requester/post_spec.rb
|
85
|
+
- spec/requester/retry_spec.rb
|
81
86
|
homepage: https://github.com/mLewisLogic/saddle
|
82
87
|
licenses:
|
83
88
|
- MIT
|
@@ -104,4 +109,6 @@ specification_version: 4
|
|
104
109
|
summary: A generic client wrapper for building service-specific wrappers. Base functionality,
|
105
110
|
meant to be extended to concrete implementations.
|
106
111
|
test_files:
|
107
|
-
- spec/
|
112
|
+
- spec/requester/get_spec.rb
|
113
|
+
- spec/requester/post_spec.rb
|
114
|
+
- spec/requester/retry_spec.rb
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
|
-
|
4
|
-
module Saddle::Middleware
|
5
|
-
|
6
|
-
# Public: Reports exceptions to airbrake
|
7
|
-
#
|
8
|
-
class AirbrakeLogging < Faraday::Middleware
|
9
|
-
|
10
|
-
def initialize(app, airbrake_api_key)
|
11
|
-
@airbrake_api_key = airbrake_api_key
|
12
|
-
super(app)
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
begin
|
17
|
-
@app.call(env)
|
18
|
-
rescue => e
|
19
|
-
::Airbrake.notify(
|
20
|
-
e,
|
21
|
-
{
|
22
|
-
:api_key => @airbrake_api_key,
|
23
|
-
}
|
24
|
-
)
|
25
|
-
raise
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
|
3
|
-
|
4
|
-
module Saddle::Middleware
|
5
|
-
|
6
|
-
# Public: Returns a default response in the case of an exception
|
7
|
-
# Expects default_response to be defined in the request of connection options, otherwise rethrows exception
|
8
|
-
class DefaultResponse < Faraday::Middleware
|
9
|
-
|
10
|
-
def call(env)
|
11
|
-
begin
|
12
|
-
@app.call(env)
|
13
|
-
rescue => e
|
14
|
-
if res = env[:request][:default_response]
|
15
|
-
return ::Faraday::Response.new(:body => res)
|
16
|
-
else
|
17
|
-
raise
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'faraday_middleware/response_middleware'
|
2
|
-
|
3
|
-
|
4
|
-
module Saddle::Middleware
|
5
|
-
|
6
|
-
# Public: Parse response bodies as JSON.
|
7
|
-
class ParseJson < FaradayMiddleware::ResponseMiddleware
|
8
|
-
MIME_TYPE = 'application/json'.freeze
|
9
|
-
|
10
|
-
dependency do
|
11
|
-
require 'json' unless defined?(::JSON)
|
12
|
-
end
|
13
|
-
|
14
|
-
define_parser do |body|
|
15
|
-
::JSON.parse body unless body.strip.empty?
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def parse_response?(env)
|
20
|
-
type = response_type(env)
|
21
|
-
super and has_body?(env) and (type.empty? or type == MIME_TYPE)
|
22
|
-
end
|
23
|
-
|
24
|
-
def has_body?(env)
|
25
|
-
body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
|
26
|
-
end
|
27
|
-
|
28
|
-
def response_type(env)
|
29
|
-
type = env[:response_headers][CONTENT_TYPE].to_s
|
30
|
-
type = type.split(';', 2).first if type.index(';')
|
31
|
-
type
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'statsd'
|
2
|
-
|
3
|
-
module Saddle::Middleware
|
4
|
-
|
5
|
-
# Public: Wraps request with statsd logging
|
6
|
-
# Expects statsd_path in request options. However, if using saddle and no statsd_path is specified
|
7
|
-
# will read call_chain and action and use them to construct a statsd_path
|
8
|
-
class StatsdLogging < Faraday::Middleware
|
9
|
-
attr_accessor :graphite_host, :graphite_port, :namespace
|
10
|
-
|
11
|
-
def initialize(app, graphite_host, graphite_port=nil, namespace=nil)
|
12
|
-
super(app)
|
13
|
-
@graphite_host = graphite_host
|
14
|
-
@graphite_port = graphite_port
|
15
|
-
@namespace = namespace
|
16
|
-
self.statsd
|
17
|
-
end
|
18
|
-
|
19
|
-
def statsd
|
20
|
-
if(@statsd.nil?)
|
21
|
-
@statsd = Statsd.new(@graphite_host, @graphite_port)
|
22
|
-
@statsd.namespace = @namespace if @namespace
|
23
|
-
end
|
24
|
-
return @statsd
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(env)
|
28
|
-
if env[:request][:statsd_path]
|
29
|
-
statsd_path = env[:request][:statsd_path]
|
30
|
-
elsif env[:request][:saddle] && env[:request][:saddle][:call_chain] && env[:request][:saddle][:action]
|
31
|
-
statsd_path = (env[:request][:saddle][:call_chain] + [env[:request][:saddle][:action]]).join(".")
|
32
|
-
end
|
33
|
-
|
34
|
-
if statsd_path
|
35
|
-
self.statsd.time statsd_path do
|
36
|
-
@app.call(env)
|
37
|
-
end
|
38
|
-
else
|
39
|
-
@app.call(env)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
data/spec/saddle_client_spec.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'saddle'
|
2
|
-
|
3
|
-
describe Saddle::Client do
|
4
|
-
|
5
|
-
context "instance" do
|
6
|
-
before :each do
|
7
|
-
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
8
|
-
stub.get('/test') {
|
9
|
-
[
|
10
|
-
200,
|
11
|
-
{'Content-Type' => 'application/x-www-form-urlencoded'},
|
12
|
-
'success'
|
13
|
-
]
|
14
|
-
}
|
15
|
-
stub.get('/test.json') {
|
16
|
-
[
|
17
|
-
200,
|
18
|
-
{'Content-Type' => 'application/json'},
|
19
|
-
{'success' => true}.to_json
|
20
|
-
]
|
21
|
-
}
|
22
|
-
end
|
23
|
-
@client = Saddle::Client.create(:stubs => stubs)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should be able to request urlencoded" do
|
27
|
-
@client.requester.get('/test').should == 'success'
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should be able to request JSON encoded" do
|
31
|
-
@client.requester.get('/test.json')['success'].should == true
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|