shin-faraday 0.4.7
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +84 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/faraday.gemspec +87 -0
- data/lib/faraday.rb +94 -0
- data/lib/faraday/adapter/action_dispatch.rb +33 -0
- data/lib/faraday/adapter/net_http.rb +59 -0
- data/lib/faraday/adapter/patron.rb +33 -0
- data/lib/faraday/adapter/test.rb +117 -0
- data/lib/faraday/adapter/typhoeus.rb +65 -0
- data/lib/faraday/builder.rb +82 -0
- data/lib/faraday/connection.rb +263 -0
- data/lib/faraday/error.rb +8 -0
- data/lib/faraday/middleware.rb +54 -0
- data/lib/faraday/request.rb +87 -0
- data/lib/faraday/request/active_support_json.rb +21 -0
- data/lib/faraday/request/yajl.rb +18 -0
- data/lib/faraday/response.rb +56 -0
- data/lib/faraday/response/active_support_json.rb +31 -0
- data/lib/faraday/response/nokogiri.rb +21 -0
- data/lib/faraday/response/yajl.rb +26 -0
- data/test/adapters/live_test.rb +141 -0
- data/test/adapters/test_middleware_test.rb +26 -0
- data/test/adapters/typhoeus_test.rb +26 -0
- data/test/connection_app_test.rb +60 -0
- data/test/connection_test.rb +284 -0
- data/test/env_test.rb +56 -0
- data/test/helper.rb +32 -0
- data/test/live_server.rb +34 -0
- data/test/request_middleware_test.rb +24 -0
- data/test/response_middleware_test.rb +44 -0
- metadata +142 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Middleware
|
3
|
+
include Rack::Utils
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :load_error, :supports_parallel_requests
|
7
|
+
alias supports_parallel_requests? supports_parallel_requests
|
8
|
+
|
9
|
+
# valid parallel managers should respond to #run with no parameters.
|
10
|
+
# otherwise, return a short wrapper around it.
|
11
|
+
def setup_parallel_manager(options = {})
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.loaded?
|
17
|
+
@load_error.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(app = nil)
|
21
|
+
@app = app
|
22
|
+
end
|
23
|
+
|
24
|
+
# assume that query and fragment are already encoded properly
|
25
|
+
def full_path_for(path, query = nil, fragment = nil)
|
26
|
+
full_path = path.dup
|
27
|
+
if query && !query.empty?
|
28
|
+
full_path << "?#{query}"
|
29
|
+
end
|
30
|
+
if fragment && !fragment.empty?
|
31
|
+
full_path << "##{fragment}"
|
32
|
+
end
|
33
|
+
full_path
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_body_for_request(env)
|
37
|
+
# if it's a string, pass it through
|
38
|
+
return if env[:body].nil? || env[:body].empty? || !env[:body].respond_to?(:each_key)
|
39
|
+
env[:request_headers]['Content-Type'] ||= 'application/x-www-form-urlencoded'
|
40
|
+
env[:body] = create_form_params(env[:body])
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_form_params(params, base = nil)
|
44
|
+
[].tap do |result|
|
45
|
+
params.each_key do |key|
|
46
|
+
key_str = base ? "#{base}[#{key}]" : key
|
47
|
+
value = params[key]
|
48
|
+
wee = (value.kind_of?(Hash) ? create_form_params(value, key_str) : "#{key_str}=#{escape(value.to_s)}")
|
49
|
+
result << wee
|
50
|
+
end
|
51
|
+
end.join("&")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Faraday
|
2
|
+
# Used to setup urls, params, headers, and the request body in a sane manner.
|
3
|
+
#
|
4
|
+
# @connection.post do |req|
|
5
|
+
# req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1'
|
6
|
+
# req.headers['b'] = '2' # header
|
7
|
+
# req['b'] = '2' # header
|
8
|
+
# req.body = 'abc'
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
class Request < Struct.new(:path, :params, :headers, :body)
|
12
|
+
extend AutoloadHelper
|
13
|
+
autoload_all 'faraday/request',
|
14
|
+
:Yajl => 'yajl',
|
15
|
+
:ActiveSupportJson => 'active_support_json'
|
16
|
+
|
17
|
+
register_lookup_modules \
|
18
|
+
:yajl => :Yajl,
|
19
|
+
:activesupport_json => :ActiveSupportJson,
|
20
|
+
:rails_json => :ActiveSupportJson,
|
21
|
+
:active_support_json => :ActiveSupportJson
|
22
|
+
|
23
|
+
def self.run(connection, request_method)
|
24
|
+
req = create
|
25
|
+
yield req if block_given?
|
26
|
+
req.run(connection, request_method)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create
|
30
|
+
req = new(nil, {}, {}, nil)
|
31
|
+
yield req if block_given?
|
32
|
+
req
|
33
|
+
end
|
34
|
+
|
35
|
+
def url(path, params = {})
|
36
|
+
self.path = path
|
37
|
+
self.params = params
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](key)
|
41
|
+
headers[key]
|
42
|
+
end
|
43
|
+
|
44
|
+
def []=(key, value)
|
45
|
+
headers[key] = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# ENV Keys
|
49
|
+
# :method - a symbolized request method (:get, :post)
|
50
|
+
# :body - the request body that will eventually be converted to a string.
|
51
|
+
# :url - Addressable::URI instance of the URI for the current request.
|
52
|
+
# :status - HTTP response status code
|
53
|
+
# :request_headers - hash of HTTP Headers to be sent to the server
|
54
|
+
# :response_headers - Hash of HTTP headers from the server
|
55
|
+
# :parallel_manager - sent if the connection is in parallel mode
|
56
|
+
# :response - the actual response object that stores the rack response
|
57
|
+
# :request - Hash of options for configuring the request.
|
58
|
+
# :timeout - open/read timeout Integer in seconds
|
59
|
+
# :open_timeout - read timeout Integer in seconds
|
60
|
+
# :proxy - Hash of proxy options
|
61
|
+
# :uri - Proxy Server URI
|
62
|
+
# :user - Proxy server username
|
63
|
+
# :password - Proxy server password
|
64
|
+
# :ssl - Hash of options for configuring SSL requests.
|
65
|
+
def to_env_hash(connection, request_method)
|
66
|
+
env_headers = connection.headers.dup
|
67
|
+
env_params = connection.params.dup
|
68
|
+
connection.merge_headers(env_headers, headers)
|
69
|
+
connection.merge_params(env_params, params)
|
70
|
+
|
71
|
+
{ :method => request_method,
|
72
|
+
:body => body,
|
73
|
+
:url => connection.build_url(path, env_params),
|
74
|
+
:request_headers => env_headers.update(headers),
|
75
|
+
:parallel_manager => connection.parallel_manager,
|
76
|
+
:response => Response.new,
|
77
|
+
:request => connection.options.merge(:proxy => connection.proxy),
|
78
|
+
:ssl => connection.ssl}
|
79
|
+
end
|
80
|
+
|
81
|
+
def run(connection, request_method)
|
82
|
+
app = connection.to_app
|
83
|
+
env = to_env_hash(connection, request_method)
|
84
|
+
app.call(env)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request::ActiveSupportJson < Faraday::Middleware
|
3
|
+
begin
|
4
|
+
if !defined?(ActiveSupport::JSON)
|
5
|
+
require 'active_support'
|
6
|
+
ActiveSupport::JSON
|
7
|
+
end
|
8
|
+
|
9
|
+
rescue LoadError, NameError => e
|
10
|
+
self.load_error = e
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:request_headers]['Content-Type'] = 'application/json'
|
15
|
+
if env[:body] && !env[:body].respond_to?(:to_str)
|
16
|
+
env[:body] = ActiveSupport::JSON.encode(env[:body])
|
17
|
+
end
|
18
|
+
@app.call env
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request::Yajl < Faraday::Middleware
|
3
|
+
begin
|
4
|
+
require 'yajl'
|
5
|
+
|
6
|
+
rescue LoadError, NameError => e
|
7
|
+
self.load_error = e
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
env[:request_headers]['Content-Type'] = 'application/json'
|
12
|
+
if env[:body] && !env[:body].respond_to?(:to_str)
|
13
|
+
env[:body] = Yajl::Encoder.encode(env[:body])
|
14
|
+
end
|
15
|
+
@app.call env
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Response
|
3
|
+
class Middleware < Faraday::Middleware
|
4
|
+
self.load_error = :abstract
|
5
|
+
|
6
|
+
# Use a response callback in case the request is parallelized.
|
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)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
self.class.register_on_complete(env)
|
17
|
+
@app.call env
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
extend AutoloadHelper
|
22
|
+
|
23
|
+
autoload_all 'faraday/response',
|
24
|
+
:Yajl => 'yajl',
|
25
|
+
:Nokogiri => 'nokogiri',
|
26
|
+
:ActiveSupportJson => 'active_support_json'
|
27
|
+
|
28
|
+
register_lookup_modules \
|
29
|
+
:yajl => :Yajl,
|
30
|
+
:nokogiri => :Nokogiri,
|
31
|
+
:activesupport_json => :ActiveSupportJson,
|
32
|
+
:rails_json => :ActiveSupportJson,
|
33
|
+
:active_support_json => :ActiveSupportJson
|
34
|
+
attr_accessor :status, :headers, :body
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
@status, @headers, @body = nil, nil, nil
|
38
|
+
@on_complete_callbacks = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_complete(&block)
|
42
|
+
@on_complete_callbacks << block
|
43
|
+
end
|
44
|
+
|
45
|
+
def finish(env)
|
46
|
+
env[:body] ||= ''
|
47
|
+
@on_complete_callbacks.each { |c| c.call(env) }
|
48
|
+
@status, @headers, @body = env[:status], env[:response_headers], env[:body]
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def success?
|
53
|
+
status == 200
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Response::ActiveSupportJson < Response::Middleware
|
3
|
+
begin
|
4
|
+
if !defined?(ActiveSupport::JSON)
|
5
|
+
require 'active_support'
|
6
|
+
ActiveSupport::JSON
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.register_on_complete(env)
|
10
|
+
env[:response].on_complete do |finished_env|
|
11
|
+
finished_env[:body] = parse(finished_env[:body])
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue LoadError, NameError => e
|
16
|
+
self.load_error = e
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(app)
|
20
|
+
super
|
21
|
+
@parser = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse(body)
|
25
|
+
ActiveSupport::JSON.decode(body)
|
26
|
+
# TODO: Maybe rescue Exception can be better ...
|
27
|
+
rescue Yajl::ParseError => e
|
28
|
+
raise Faraday::Error::ParsingError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Response::Nokogiri < Faraday::Response::Middleware
|
3
|
+
begin
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
def self.register_on_complete(env)
|
7
|
+
env[:response].on_complete do |finished_env|
|
8
|
+
finished_env[:body] = ::Nokogiri::XML(finished_env[:body])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
rescue LoadError, NameError => e
|
12
|
+
self.load_error = e
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(app)
|
17
|
+
super
|
18
|
+
@parser = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Response::Yajl < Response::Middleware
|
3
|
+
begin
|
4
|
+
require 'yajl'
|
5
|
+
|
6
|
+
def self.register_on_complete(env)
|
7
|
+
env[:response].on_complete do |finished_env|
|
8
|
+
finished_env[:body] = parse(finished_env[:body])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
rescue LoadError, NameError => e
|
12
|
+
self.load_error = e
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(app)
|
16
|
+
super
|
17
|
+
@parser = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse(body)
|
21
|
+
Yajl::Parser.parse(body)
|
22
|
+
rescue Yajl::ParseError => e
|
23
|
+
raise Faraday::Error::ParsingError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
|
2
|
+
|
3
|
+
if Faraday::TestCase::LIVE_SERVER
|
4
|
+
module Adapters
|
5
|
+
class LiveTest < Faraday::TestCase
|
6
|
+
(Faraday::Adapter.all_loaded_constants + [:default]).each do |adapter|
|
7
|
+
define_method "test_#{adapter}_GET_retrieves_the_response_body" do
|
8
|
+
assert_equal 'hello world', create_connection(adapter).get('hello_world').body
|
9
|
+
end
|
10
|
+
|
11
|
+
define_method "test_#{adapter}_GET_send_url_encoded_params" do
|
12
|
+
resp = create_connection(adapter).get do |req|
|
13
|
+
req.url 'hello', 'name' => 'zack'
|
14
|
+
end
|
15
|
+
assert_equal('hello zack', resp.body)
|
16
|
+
end
|
17
|
+
|
18
|
+
define_method "test_#{adapter}_GET_retrieves_the_response_headers" do
|
19
|
+
assert_equal 'text/html', create_connection(adapter).get('hello_world').headers['content-type']
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method "test_#{adapter}_POST_send_url_encoded_params" do
|
23
|
+
resp = create_connection(adapter).post do |req|
|
24
|
+
req.url 'echo_name'
|
25
|
+
req.body = {'name' => 'zack'}
|
26
|
+
end
|
27
|
+
assert_equal %("zack"), resp.body
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method "test_#{adapter}_POST_send_url_encoded_nested_params" do
|
31
|
+
resp = create_connection(adapter).post do |req|
|
32
|
+
req.url 'echo_name'
|
33
|
+
req.body = {'name' => {'first' => 'zack'}}
|
34
|
+
end
|
35
|
+
assert_equal %({"first"=>"zack"}), resp.body
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method "test_#{adapter}_POST_retrieves_the_response_headers" do
|
39
|
+
assert_equal 'text/html', create_connection(adapter).post('echo_name').headers['content-type']
|
40
|
+
end
|
41
|
+
|
42
|
+
# http://github.com/toland/patron/issues/#issue/9
|
43
|
+
if ENV['FORCE'] || adapter != Faraday::Adapter::Patron
|
44
|
+
define_method "test_#{adapter}_PUT_send_url_encoded_params" do
|
45
|
+
resp = create_connection(adapter).put do |req|
|
46
|
+
req.url 'echo_name'
|
47
|
+
req.body = {'name' => 'zack'}
|
48
|
+
end
|
49
|
+
assert_equal %("zack"), resp.body
|
50
|
+
end
|
51
|
+
|
52
|
+
define_method "test_#{adapter}_PUT_send_url_encoded_nested_params" do
|
53
|
+
resp = create_connection(adapter).put do |req|
|
54
|
+
req.url 'echo_name'
|
55
|
+
req.body = {'name' => {'first' => 'zack'}}
|
56
|
+
end
|
57
|
+
assert_equal %({"first"=>"zack"}), resp.body
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method "test_#{adapter}_PUT_retrieves_the_response_headers" do
|
61
|
+
assert_equal 'text/html', create_connection(adapter).put('echo_name').headers['content-type']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# http://github.com/pauldix/typhoeus/issues#issue/7
|
66
|
+
if ENV['FORCE'] || adapter != Faraday::Adapter::Typhoeus
|
67
|
+
define_method "test_#{adapter}_HEAD_send_url_encoded_params" do
|
68
|
+
resp = create_connection(adapter).head do |req|
|
69
|
+
req.url 'hello', 'name' => 'zack'
|
70
|
+
end
|
71
|
+
assert_equal 'text/html', resp.headers['content-type']
|
72
|
+
end
|
73
|
+
|
74
|
+
define_method "test_#{adapter}_HEAD_retrieves_no_response_body" do
|
75
|
+
assert_equal '', create_connection(adapter).head('hello_world').body.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
define_method "test_#{adapter}_HEAD_retrieves_the_response_headers" do
|
79
|
+
assert_equal 'text/html', create_connection(adapter).head('hello_world').headers['content-type']
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
define_method "test_#{adapter}_DELETE_retrieves_the_response_headers" do
|
84
|
+
assert_equal 'text/html', create_connection(adapter).delete('delete_with_json').headers['content-type']
|
85
|
+
end
|
86
|
+
|
87
|
+
define_method "test_#{adapter}_DELETE_retrieves_the_body" do
|
88
|
+
assert_match /deleted/, create_connection(adapter).delete('delete_with_json').body
|
89
|
+
end
|
90
|
+
|
91
|
+
define_method "test_#{adapter}_async_requests_clear_parallel_manager_after_running_a_single_request" do
|
92
|
+
connection = create_connection(adapter)
|
93
|
+
assert !connection.in_parallel?
|
94
|
+
resp = connection.get('hello_world')
|
95
|
+
assert !connection.in_parallel?
|
96
|
+
assert_equal 'hello world', connection.get('hello_world').body
|
97
|
+
end
|
98
|
+
|
99
|
+
define_method "test_#{adapter}_async_requests_uses_parallel_manager_to_run_multiple_json_requests" do
|
100
|
+
resp1, resp2 = nil, nil
|
101
|
+
|
102
|
+
connection = create_connection(adapter)
|
103
|
+
adapter = real_adapter_for(adapter)
|
104
|
+
|
105
|
+
connection.in_parallel(adapter.setup_parallel_manager) do
|
106
|
+
resp1 = connection.get('json')
|
107
|
+
resp2 = connection.get('json')
|
108
|
+
if adapter.supports_parallel_requests?
|
109
|
+
assert connection.in_parallel?
|
110
|
+
assert_nil resp1.body
|
111
|
+
assert_nil resp2.body
|
112
|
+
end
|
113
|
+
end
|
114
|
+
assert !connection.in_parallel?
|
115
|
+
assert_equal '[1,2,3]', resp1.body
|
116
|
+
assert_equal '[1,2,3]', resp2.body
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def create_connection(adapter)
|
121
|
+
if adapter == :default
|
122
|
+
conn = Faraday.default_connection
|
123
|
+
conn.url_prefix = LIVE_SERVER
|
124
|
+
conn
|
125
|
+
else
|
126
|
+
Faraday::Connection.new LIVE_SERVER do |b|
|
127
|
+
b.use adapter
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def real_adapter_for(adapter)
|
133
|
+
if adapter == :default
|
134
|
+
Faraday::Adapter.lookup_module(Faraday.default_adapter)
|
135
|
+
else
|
136
|
+
adapter
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|