faraday 0.5.7 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -8
- data/README.md +99 -20
- data/faraday.gemspec +9 -11
- data/lib/faraday.rb +1 -1
- data/lib/faraday/adapter.rb +11 -86
- data/lib/faraday/adapter/action_dispatch.rb +3 -12
- data/lib/faraday/adapter/em_synchrony.rb +9 -24
- data/lib/faraday/adapter/excon.rb +7 -19
- data/lib/faraday/adapter/net_http.rb +37 -35
- data/lib/faraday/adapter/patron.rb +16 -23
- data/lib/faraday/adapter/test.rb +4 -10
- data/lib/faraday/adapter/typhoeus.rb +11 -39
- data/lib/faraday/builder.rb +82 -33
- data/lib/faraday/connection.rb +3 -10
- data/lib/faraday/error.rb +20 -15
- data/lib/faraday/middleware.rb +7 -2
- data/lib/faraday/request.rb +13 -10
- data/lib/faraday/request/json.rb +31 -0
- data/lib/faraday/request/multipart.rb +63 -0
- data/lib/faraday/request/url_encoded.rb +37 -0
- data/lib/faraday/response.rb +72 -30
- data/lib/faraday/response/logger.rb +34 -0
- data/lib/faraday/response/raise_error.rb +16 -0
- data/lib/faraday/upload_io.rb +14 -6
- data/lib/faraday/utils.rb +54 -17
- data/test/adapters/live_test.rb +36 -14
- data/test/adapters/logger_test.rb +1 -1
- data/test/adapters/net_http_test.rb +33 -0
- data/test/connection_test.rb +0 -39
- data/test/env_test.rb +84 -6
- data/test/helper.rb +17 -8
- data/test/live_server.rb +19 -17
- data/test/middleware_stack_test.rb +91 -0
- data/test/request_middleware_test.rb +75 -21
- data/test/response_middleware_test.rb +34 -31
- metadata +21 -17
- data/lib/faraday/adapter/logger.rb +0 -32
- data/lib/faraday/request/active_support_json.rb +0 -21
- data/lib/faraday/request/yajl.rb +0 -18
- data/lib/faraday/response/active_support_json.rb +0 -30
- data/lib/faraday/response/yajl.rb +0 -26
- data/test/adapters/typhoeus_test.rb +0 -31
- data/test/connection_app_test.rb +0 -60
- data/test/form_post_test.rb +0 -58
- data/test/multipart_test.rb +0 -48
data/lib/faraday/error.rb
CHANGED
@@ -1,28 +1,33 @@
|
|
1
1
|
module Faraday
|
2
2
|
module Error
|
3
3
|
class ClientError < StandardError
|
4
|
-
|
5
|
-
@inner_exception = exception
|
6
|
-
end
|
4
|
+
attr_reader :response
|
7
5
|
|
8
|
-
def
|
9
|
-
@
|
10
|
-
|
11
|
-
@inner_exception.to_s
|
12
|
-
end
|
6
|
+
def initialize(ex)
|
7
|
+
@wrapped_exception = nil
|
8
|
+
@response = nil
|
13
9
|
|
14
|
-
|
15
|
-
|
10
|
+
if ex.respond_to?(:backtrace)
|
11
|
+
super(ex.message)
|
12
|
+
@wrapped_exception = ex
|
13
|
+
elsif ex.respond_to?(:each_key)
|
14
|
+
super("the server responded with status #{ex[:status]}")
|
15
|
+
@response = ex
|
16
|
+
else
|
17
|
+
super(ex.to_s)
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
def backtrace
|
22
|
+
if @wrapped_exception
|
23
|
+
@wrapped_exception.backtrace
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
22
27
|
end
|
23
28
|
|
24
29
|
def inspect
|
25
|
-
|
30
|
+
%(#<#{self.class}>)
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
data/lib/faraday/middleware.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Faraday
|
2
2
|
class Middleware
|
3
|
-
include Rack::Utils
|
4
|
-
|
5
3
|
class << self
|
6
4
|
attr_accessor :load_error, :supports_parallel_requests
|
7
5
|
alias supports_parallel_requests? supports_parallel_requests
|
@@ -13,6 +11,13 @@ module Faraday
|
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
14
|
+
# Executes a block which should try to require and reference dependent libraries
|
15
|
+
def self.dependency(lib = nil)
|
16
|
+
lib ? require(lib) : yield
|
17
|
+
rescue LoadError, NameError => error
|
18
|
+
self.load_error = error
|
19
|
+
end
|
20
|
+
|
16
21
|
def self.loaded?
|
17
22
|
@load_error.nil?
|
18
23
|
end
|
data/lib/faraday/request.rb
CHANGED
@@ -11,15 +11,16 @@ module Faraday
|
|
11
11
|
#
|
12
12
|
class Request < Struct.new(:path, :params, :headers, :body)
|
13
13
|
extend AutoloadHelper
|
14
|
+
|
14
15
|
autoload_all 'faraday/request',
|
15
|
-
:
|
16
|
-
:
|
16
|
+
:JSON => 'json',
|
17
|
+
:UrlEncoded => 'url_encoded',
|
18
|
+
:Multipart => 'multipart'
|
17
19
|
|
18
20
|
register_lookup_modules \
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:active_support_json => :ActiveSupportJson
|
21
|
+
:json => :JSON,
|
22
|
+
:url_encoded => :UrlEncoded,
|
23
|
+
:multipart => :Multipart
|
23
24
|
|
24
25
|
def self.run(connection, request_method)
|
25
26
|
req = create
|
@@ -54,7 +55,6 @@ module Faraday
|
|
54
55
|
# :request_headers - hash of HTTP Headers to be sent to the server
|
55
56
|
# :response_headers - Hash of HTTP headers from the server
|
56
57
|
# :parallel_manager - sent if the connection is in parallel mode
|
57
|
-
# :response - the actual response object that stores the rack response
|
58
58
|
# :request - Hash of options for configuring the request.
|
59
59
|
# :timeout - open/read timeout Integer in seconds
|
60
60
|
# :open_timeout - read timeout Integer in seconds
|
@@ -74,15 +74,18 @@ module Faraday
|
|
74
74
|
:url => connection.build_url(path, env_params),
|
75
75
|
:request_headers => env_headers,
|
76
76
|
:parallel_manager => connection.parallel_manager,
|
77
|
-
:response => Response.new,
|
78
77
|
:request => connection.options.merge(:proxy => connection.proxy),
|
79
78
|
:ssl => connection.ssl}
|
80
79
|
end
|
81
80
|
|
82
81
|
def run(connection, request_method)
|
83
|
-
app =
|
82
|
+
app = lambda { |env|
|
83
|
+
response = Response.new
|
84
|
+
response.finish(env) unless env[:parallel_manager]
|
85
|
+
env[:response] = response
|
86
|
+
}
|
84
87
|
env = to_env_hash(connection, request_method)
|
85
|
-
app.call(env)
|
88
|
+
connection.builder.to_app(app).call(env)
|
86
89
|
end
|
87
90
|
end
|
88
91
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request::JSON < Request::UrlEncoded
|
3
|
+
self.mime_type = 'application/json'.freeze
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
# loads the JSON encoder either from yajl-ruby or activesupport
|
10
|
+
dependency do
|
11
|
+
begin
|
12
|
+
require 'yajl'
|
13
|
+
self.adapter = Yajl::Encoder
|
14
|
+
rescue LoadError, NameError
|
15
|
+
require 'active_support/core_ext/module/attribute_accessors' # AS 2.3.11
|
16
|
+
require 'active_support/core_ext/kernel/reporting' # AS 2.3.11
|
17
|
+
require 'active_support/json/encoding'
|
18
|
+
require 'active_support/ordered_hash' # AS 3.0.4
|
19
|
+
self.adapter = ActiveSupport::JSON
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
match_content_type(env) do |data|
|
25
|
+
# encode with the first successfully loaded adapter
|
26
|
+
env[:body] = self.class.adapter.encode data
|
27
|
+
end
|
28
|
+
@app.call env
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request::Multipart < Request::UrlEncoded
|
3
|
+
self.mime_type = 'multipart/form-data'.freeze
|
4
|
+
DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
match_content_type(env) do |params|
|
8
|
+
env[:request] ||= {}
|
9
|
+
env[:request][:boundary] ||= DEFAULT_BOUNDARY
|
10
|
+
env[:request_headers][CONTENT_TYPE] += ";boundary=#{env[:request][:boundary]}"
|
11
|
+
env[:body] = create_multipart(env, params)
|
12
|
+
end
|
13
|
+
@app.call env
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_request?(env)
|
17
|
+
type = request_type(env)
|
18
|
+
env[:body].respond_to?(:each_key) and !env[:body].empty? and (
|
19
|
+
(type.empty? and has_multipart?(env[:body])) or
|
20
|
+
type == self.class.mime_type
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_multipart?(body)
|
25
|
+
body.values.each do |val|
|
26
|
+
if val.respond_to?(:content_type)
|
27
|
+
return true
|
28
|
+
elsif val.respond_to?(:values)
|
29
|
+
return true if has_multipart?(val)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_multipart(env, params)
|
36
|
+
boundary = env[:request][:boundary]
|
37
|
+
parts = process_params(params) do |key, value|
|
38
|
+
Faraday::Parts::Part.new(boundary, key, value)
|
39
|
+
end
|
40
|
+
parts << Faraday::Parts::EpiloguePart.new(boundary)
|
41
|
+
|
42
|
+
body = Faraday::CompositeReadIO.new(parts)
|
43
|
+
env[:request_headers]['Content-Length'] = body.length.to_s
|
44
|
+
return body
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_params(params, prefix = nil, pieces = nil, &block)
|
48
|
+
params.inject(pieces || []) do |all, (key, value)|
|
49
|
+
key = "#{prefix}[#{key}]" if prefix
|
50
|
+
|
51
|
+
case value
|
52
|
+
when Array
|
53
|
+
values = value.inject([]) { |a,v| a << [nil, v] }
|
54
|
+
process_params(values, key, all, &block)
|
55
|
+
when Hash
|
56
|
+
process_params(value, key, all, &block)
|
57
|
+
else
|
58
|
+
all << block.call(key, value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request::UrlEncoded < Faraday::Middleware
|
3
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :mime_type
|
7
|
+
end
|
8
|
+
self.mime_type = 'application/x-www-form-urlencoded'.freeze
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
match_content_type(env) do |data|
|
12
|
+
env[:body] = Faraday::Utils.build_nested_query data
|
13
|
+
end
|
14
|
+
@app.call env
|
15
|
+
end
|
16
|
+
|
17
|
+
def match_content_type(env)
|
18
|
+
type = request_type(env)
|
19
|
+
|
20
|
+
if process_request?(env)
|
21
|
+
env[:request_headers][CONTENT_TYPE] ||= self.class.mime_type
|
22
|
+
yield env[:body] unless env[:body].respond_to?(:to_str)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_request?(env)
|
27
|
+
type = request_type(env)
|
28
|
+
env[:body] and (type.empty? or type == self.class.mime_type)
|
29
|
+
end
|
30
|
+
|
31
|
+
def request_type(env)
|
32
|
+
type = env[:request_headers][CONTENT_TYPE].to_s
|
33
|
+
type = type.split(';', 2).first if type.index(';')
|
34
|
+
type
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/faraday/response.rb
CHANGED
@@ -1,56 +1,98 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
class Response
|
5
|
+
# Used for simple response middleware.
|
3
6
|
class Middleware < Faraday::Middleware
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# env[:response].on_complete do |finished_env|
|
9
|
-
# finished_env[:body] = do_stuff_to(finished_env[:body])
|
10
|
-
# end
|
11
|
-
#
|
12
|
-
def self.register_on_complete(env)
|
7
|
+
def call(env)
|
8
|
+
@app.call(env).on_complete do |env|
|
9
|
+
on_complete(env)
|
10
|
+
end
|
13
11
|
end
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# Override this to modify the environment after the response has finished.
|
14
|
+
# Calls the `parse` method if defined
|
15
|
+
def on_complete(env)
|
16
|
+
if respond_to? :parse
|
17
|
+
env[:body] = parse(env[:body])
|
18
|
+
end
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
22
|
+
extend Forwardable
|
21
23
|
extend AutoloadHelper
|
22
24
|
|
23
25
|
autoload_all 'faraday/response',
|
24
|
-
:
|
25
|
-
:
|
26
|
+
:RaiseError => 'raise_error',
|
27
|
+
:Logger => 'logger'
|
26
28
|
|
27
29
|
register_lookup_modules \
|
28
|
-
:
|
29
|
-
:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def initialize
|
35
|
-
@status, @headers, @body = nil, nil, nil
|
30
|
+
:raise_error => :RaiseError,
|
31
|
+
:logger => :Logger
|
32
|
+
|
33
|
+
def initialize(env = nil)
|
34
|
+
@env = env
|
36
35
|
@on_complete_callbacks = []
|
37
36
|
end
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
attr_reader :env
|
39
|
+
alias_method :to_hash, :env
|
40
|
+
|
41
|
+
def status
|
42
|
+
finished? ? env[:status] : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def headers
|
46
|
+
finished? ? env[:response_headers] : {}
|
47
|
+
end
|
48
|
+
def_delegator :headers, :[]
|
49
|
+
|
50
|
+
def body
|
51
|
+
finished? ? env[:body] : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def finished?
|
55
|
+
!!env
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_complete
|
59
|
+
if not finished?
|
60
|
+
@on_complete_callbacks << Proc.new
|
61
|
+
else
|
62
|
+
yield env
|
63
|
+
end
|
64
|
+
return self
|
41
65
|
end
|
42
66
|
|
43
67
|
def finish(env)
|
44
|
-
|
45
|
-
env
|
46
|
-
env
|
47
|
-
|
48
|
-
@status, @headers, @body = env[:status], env[:response_headers], env[:body]
|
49
|
-
self
|
68
|
+
raise "response already finished" if finished?
|
69
|
+
@env = env
|
70
|
+
@on_complete_callbacks.each { |callback| callback.call(env) }
|
71
|
+
return self
|
50
72
|
end
|
51
73
|
|
52
74
|
def success?
|
53
75
|
status == 200
|
54
76
|
end
|
77
|
+
|
78
|
+
# because @on_complete_callbacks cannot be marshalled
|
79
|
+
def marshal_dump
|
80
|
+
!finished? ? nil : {
|
81
|
+
:status => @env[:status], :body => @env[:body],
|
82
|
+
:response_headers => @env[:response_headers]
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def marshal_load(env)
|
87
|
+
@env = env
|
88
|
+
end
|
89
|
+
|
90
|
+
# Expand the env with more properties, without overriding existing ones.
|
91
|
+
# Useful for applying request params after restoring a marshalled Response.
|
92
|
+
def apply_request(request_env)
|
93
|
+
raise "response didn't finish yet" unless finished?
|
94
|
+
@env = request_env.merge @env
|
95
|
+
return self
|
96
|
+
end
|
55
97
|
end
|
56
98
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
class Response::Logger < Response::Middleware
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def initialize(app, logger = nil)
|
8
|
+
super(app)
|
9
|
+
@logger = logger || begin
|
10
|
+
require 'logger'
|
11
|
+
::Logger.new(STDOUT)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
info "#{env[:method]} #{env[:url].to_s}"
|
19
|
+
debug('request') { dump_headers env[:request_headers] }
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_complete(env)
|
24
|
+
info('Status') { env[:status].to_s }
|
25
|
+
debug('response') { dump_headers env[:response_headers] }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def dump_headers(headers)
|
31
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Response::RaiseError < Response::Middleware
|
3
|
+
def on_complete(env)
|
4
|
+
case env[:status]
|
5
|
+
when 404
|
6
|
+
raise Faraday::Error::ResourceNotFound, response_values(env)
|
7
|
+
when 400...600
|
8
|
+
raise Faraday::Error::ClientError, response_values(env)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def response_values(env)
|
13
|
+
{:status => env[:status], :headers => env[:response_headers], :body => env[:body]}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/faraday/upload_io.rb
CHANGED
@@ -3,13 +3,21 @@ begin
|
|
3
3
|
require 'parts'
|
4
4
|
require 'stringio'
|
5
5
|
rescue LoadError
|
6
|
-
puts "Install the multipart-post gem."
|
6
|
+
$stderr.puts "Install the multipart-post gem."
|
7
7
|
raise
|
8
8
|
end
|
9
9
|
|
10
|
-
# Auto-load multipart-post gem on first request.
|
11
10
|
module Faraday
|
12
|
-
CompositeReadIO
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
class CompositeReadIO < ::CompositeReadIO
|
12
|
+
attr_reader :length
|
13
|
+
|
14
|
+
def initialize(parts)
|
15
|
+
@length = parts.inject(0) { |sum, part| sum + part.length }
|
16
|
+
ios = parts.map{ |part| part.to_io }
|
17
|
+
super(*ios)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
UploadIO = ::UploadIO
|
22
|
+
Parts = ::Parts
|
23
|
+
end
|