faraday 0.4.6 → 0.5.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 +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +84 -0
- data/Rakefile +111 -34
- data/faraday.gemspec +85 -82
- data/lib/faraday.rb +17 -26
- data/lib/faraday/adapter.rb +102 -0
- data/lib/faraday/adapter/action_dispatch.rb +39 -0
- data/lib/faraday/adapter/net_http.rb +20 -8
- data/lib/faraday/adapter/patron.rb +10 -4
- data/lib/faraday/adapter/test.rb +28 -15
- data/lib/faraday/adapter/typhoeus.rb +16 -6
- data/lib/faraday/builder.rb +6 -6
- data/lib/faraday/connection.rb +33 -46
- data/lib/faraday/error.rb +25 -1
- data/lib/faraday/middleware.rb +0 -30
- data/lib/faraday/request.rb +5 -5
- data/lib/faraday/request/active_support_json.rb +1 -1
- data/lib/faraday/request/yajl.rb +1 -1
- data/lib/faraday/response/active_support_json.rb +9 -2
- data/lib/faraday/response/yajl.rb +8 -2
- data/lib/faraday/upload_io.rb +15 -0
- data/lib/faraday/utils.rb +64 -0
- data/test/adapters/live_test.rb +24 -15
- data/test/adapters/test_middleware_test.rb +11 -0
- data/test/connection_test.rb +6 -7
- data/test/env_test.rb +2 -2
- data/test/form_post_test.rb +42 -0
- data/test/helper.rb +6 -2
- data/test/live_server.rb +6 -1
- data/test/multipart_test.rb +48 -0
- data/test/request_middleware_test.rb +9 -2
- data/test/response_middleware_test.rb +8 -1
- metadata +75 -29
- data/.document +0 -5
- data/.gitignore +0 -21
- data/README.rdoc +0 -86
- data/VERSION +0 -1
data/lib/faraday/connection.rb
CHANGED
@@ -4,14 +4,7 @@ require 'base64'
|
|
4
4
|
|
5
5
|
module Faraday
|
6
6
|
class Connection
|
7
|
-
include Addressable,
|
8
|
-
|
9
|
-
HEADERS = Hash.new { |h, k| k.respond_to?(:to_str) ? k : k.to_s.capitalize }.update \
|
10
|
-
:content_type => "Content-Type",
|
11
|
-
:content_length => "Content-Length",
|
12
|
-
:accept_charset => "Accept-Charset",
|
13
|
-
:accept_encoding => "Accept-Encoding"
|
14
|
-
HEADERS.values.each { |v| v.freeze }
|
7
|
+
include Addressable, Faraday::Utils
|
15
8
|
|
16
9
|
METHODS = Set.new [:get, :post, :put, :delete, :head]
|
17
10
|
METHODS_WITH_BODIES = Set.new [:post, :put]
|
@@ -38,35 +31,53 @@ module Faraday
|
|
38
31
|
proxy(options[:proxy])
|
39
32
|
merge_params @params, options[:params] if options[:params]
|
40
33
|
merge_headers @headers, options[:headers] if options[:headers]
|
34
|
+
|
41
35
|
if block
|
42
|
-
@builder = Builder.
|
36
|
+
@builder = Builder.new
|
37
|
+
@builder.build { block.call(self) }
|
43
38
|
else
|
44
39
|
@builder = options[:builder] || Builder.new
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
43
|
+
def use(klass, *args, &block)
|
44
|
+
@builder.use(klass, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def request(key, *args, &block)
|
48
|
+
@builder.request(key, *args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def response(key, *args, &block)
|
52
|
+
@builder.response(key, *args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def adapter(key, *args, &block)
|
56
|
+
@builder.adapter(key, *args, &block)
|
57
|
+
end
|
58
|
+
|
48
59
|
def build(options = {}, &block)
|
49
60
|
@builder.build(options, &block)
|
50
61
|
end
|
51
62
|
|
52
63
|
def get(url = nil, headers = nil, &block)
|
53
|
-
run_request
|
64
|
+
run_request(:get, url, nil, headers, &block)
|
54
65
|
end
|
55
66
|
|
56
67
|
def post(url = nil, body = nil, headers = nil, &block)
|
57
|
-
run_request
|
68
|
+
run_request(:post, url, body, headers, &block)
|
58
69
|
end
|
59
70
|
|
60
71
|
def put(url = nil, body = nil, headers = nil, &block)
|
61
|
-
run_request
|
72
|
+
run_request(:put, url, body, headers, &block)
|
62
73
|
end
|
63
74
|
|
64
75
|
def head(url = nil, headers = nil, &block)
|
65
|
-
run_request
|
76
|
+
run_request(:head, url, nil, headers, &block)
|
66
77
|
end
|
67
78
|
|
68
79
|
def delete(url = nil, headers = nil, &block)
|
69
|
-
run_request
|
80
|
+
run_request(:delete, url, nil, headers, &block)
|
70
81
|
end
|
71
82
|
|
72
83
|
def basic_auth(login, pass)
|
@@ -98,7 +109,7 @@ module Faraday
|
|
98
109
|
def proxy(arg = nil)
|
99
110
|
return @proxy if arg.nil?
|
100
111
|
|
101
|
-
@proxy =
|
112
|
+
@proxy =
|
102
113
|
case arg
|
103
114
|
when String then {:uri => proxy_arg_to_uri(arg)}
|
104
115
|
when URI then {:uri => arg}
|
@@ -112,7 +123,7 @@ module Faraday
|
|
112
123
|
end
|
113
124
|
|
114
125
|
# Parses the giving url with Addressable::URI and stores the individual
|
115
|
-
# components in this connection. These components serve as defaults for
|
126
|
+
# components in this connection. These components serve as defaults for
|
116
127
|
# requests made by this connection.
|
117
128
|
#
|
118
129
|
# conn = Faraday::Connection.new { ... }
|
@@ -131,6 +142,9 @@ module Faraday
|
|
131
142
|
if uri.query && !uri.query.empty?
|
132
143
|
merge_params @params, parse_query(uri.query)
|
133
144
|
end
|
145
|
+
if uri.user && uri.password
|
146
|
+
basic_auth(uri.user, uri.password)
|
147
|
+
end
|
134
148
|
end
|
135
149
|
|
136
150
|
# Ensures that the path prefix always has a leading / and no trailing /
|
@@ -160,7 +174,7 @@ module Faraday
|
|
160
174
|
end
|
161
175
|
end
|
162
176
|
|
163
|
-
# Takes a relative url for a request and combines it with the defaults
|
177
|
+
# Takes a relative url for a request and combines it with the defaults
|
164
178
|
# set on the connection instance.
|
165
179
|
#
|
166
180
|
# conn = Faraday::Connection.new { ... }
|
@@ -190,42 +204,15 @@ module Faraday
|
|
190
204
|
def replace_query(uri, params)
|
191
205
|
url_params = @params.dup
|
192
206
|
if uri.query && !uri.query.empty?
|
193
|
-
merge_params
|
207
|
+
merge_params(url_params, parse_query(uri.query))
|
194
208
|
end
|
195
209
|
if params && !params.empty?
|
196
|
-
merge_params
|
210
|
+
merge_params(url_params, params)
|
197
211
|
end
|
198
212
|
uri.query = url_params.empty? ? nil : build_query(url_params)
|
199
213
|
uri
|
200
214
|
end
|
201
215
|
|
202
|
-
# turns param keys into strings
|
203
|
-
def merge_params(existing_params, new_params)
|
204
|
-
new_params.each do |key, value|
|
205
|
-
existing_params[key.to_s] = value
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# turns headers keys and values into strings. Look up symbol keys in the
|
210
|
-
# the HEADERS hash.
|
211
|
-
#
|
212
|
-
# h = merge_headers(HeaderHash.new, :content_type => 'text/plain')
|
213
|
-
# h['Content-Type'] # = 'text/plain'
|
214
|
-
#
|
215
|
-
def merge_headers(existing_headers, new_headers)
|
216
|
-
new_headers.each do |key, value|
|
217
|
-
existing_headers[HEADERS[key]] = value.to_s
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Be sure to URI escape '+' symbols to %2B. Otherwise, they get interpreted
|
222
|
-
# as spaces.
|
223
|
-
def escape(s)
|
224
|
-
s.to_s.gsub(/([^a-zA-Z0-9_.-]+)/n) do
|
225
|
-
'%' << $1.unpack('H2'*bytesize($1)).join('%').tap { |c| c.upcase! }
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
216
|
def proxy_arg_to_uri(arg)
|
230
217
|
case arg
|
231
218
|
when String then URI.parse(arg)
|
data/lib/faraday/error.rb
CHANGED
@@ -1,7 +1,31 @@
|
|
1
1
|
module Faraday
|
2
2
|
module Error
|
3
|
-
class ClientError
|
3
|
+
class ClientError < StandardError
|
4
|
+
def initialize(exception)
|
5
|
+
@inner_exception = exception
|
6
|
+
end
|
7
|
+
|
8
|
+
def message
|
9
|
+
@inner_exception.message
|
10
|
+
end
|
11
|
+
|
12
|
+
def backtrace
|
13
|
+
@inner_exception.backtrace
|
14
|
+
end
|
15
|
+
|
16
|
+
alias to_str message
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
@inner_exception.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
@inner_exception.inspect
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
4
27
|
class ConnectionFailed < ClientError; end
|
5
28
|
class ResourceNotFound < ClientError; end
|
29
|
+
class ParsingError < ClientError; end
|
6
30
|
end
|
7
31
|
end
|
data/lib/faraday/middleware.rb
CHANGED
@@ -20,35 +20,5 @@ module Faraday
|
|
20
20
|
def initialize(app = nil)
|
21
21
|
@app = app
|
22
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
23
|
end
|
54
24
|
end
|
data/lib/faraday/request.rb
CHANGED
@@ -65,11 +65,11 @@ module Faraday
|
|
65
65
|
def to_env_hash(connection, request_method)
|
66
66
|
env_headers = connection.headers.dup
|
67
67
|
env_params = connection.params.dup
|
68
|
-
connection.merge_headers
|
69
|
-
connection.merge_params
|
68
|
+
connection.merge_headers(env_headers, headers)
|
69
|
+
connection.merge_params(env_params, params)
|
70
70
|
|
71
|
-
{ :method => request_method,
|
72
|
-
:body => body,
|
71
|
+
{ :method => request_method,
|
72
|
+
:body => body,
|
73
73
|
:url => connection.build_url(path, env_params),
|
74
74
|
:request_headers => env_headers.update(headers),
|
75
75
|
:parallel_manager => connection.parallel_manager,
|
@@ -84,4 +84,4 @@ module Faraday
|
|
84
84
|
app.call(env)
|
85
85
|
end
|
86
86
|
end
|
87
|
-
end
|
87
|
+
end
|
@@ -13,7 +13,7 @@ module Faraday
|
|
13
13
|
def call(env)
|
14
14
|
env[:request_headers]['Content-Type'] = 'application/json'
|
15
15
|
if env[:body] && !env[:body].respond_to?(:to_str)
|
16
|
-
env[:body] = ActiveSupport::JSON.encode
|
16
|
+
env[:body] = ActiveSupport::JSON.encode(env[:body])
|
17
17
|
end
|
18
18
|
@app.call env
|
19
19
|
end
|
data/lib/faraday/request/yajl.rb
CHANGED
@@ -10,7 +10,7 @@ module Faraday
|
|
10
10
|
def call(env)
|
11
11
|
env[:request_headers]['Content-Type'] = 'application/json'
|
12
12
|
if env[:body] && !env[:body].respond_to?(:to_str)
|
13
|
-
env[:body] = Yajl::Encoder.encode
|
13
|
+
env[:body] = Yajl::Encoder.encode(env[:body])
|
14
14
|
end
|
15
15
|
@app.call env
|
16
16
|
end
|
@@ -8,16 +8,23 @@ module Faraday
|
|
8
8
|
|
9
9
|
def self.register_on_complete(env)
|
10
10
|
env[:response].on_complete do |finished_env|
|
11
|
-
finished_env[:body] =
|
11
|
+
finished_env[:body] = parse(finished_env[:body])
|
12
|
+
|
12
13
|
end
|
13
14
|
end
|
14
15
|
rescue LoadError, NameError => e
|
15
16
|
self.load_error = e
|
16
17
|
end
|
17
|
-
|
18
|
+
|
18
19
|
def initialize(app)
|
19
20
|
super
|
20
21
|
@parser = nil
|
21
22
|
end
|
23
|
+
|
24
|
+
def self.parse(body)
|
25
|
+
ActiveSupport::JSON.decode(body)
|
26
|
+
rescue Object => err
|
27
|
+
raise Faraday::Error::ParsingError.new(err)
|
28
|
+
end
|
22
29
|
end
|
23
30
|
end
|
@@ -5,16 +5,22 @@ module Faraday
|
|
5
5
|
|
6
6
|
def self.register_on_complete(env)
|
7
7
|
env[:response].on_complete do |finished_env|
|
8
|
-
finished_env[:body] =
|
8
|
+
finished_env[:body] = parse(finished_env[:body])
|
9
9
|
end
|
10
10
|
end
|
11
11
|
rescue LoadError, NameError => e
|
12
12
|
self.load_error = e
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def initialize(app)
|
16
16
|
super
|
17
17
|
@parser = nil
|
18
18
|
end
|
19
|
+
|
20
|
+
def self.parse(body)
|
21
|
+
Yajl::Parser.parse(body)
|
22
|
+
rescue Object => err
|
23
|
+
raise Faraday::Error::ParsingError.new(err)
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'composite_io'
|
3
|
+
require 'parts'
|
4
|
+
require 'stringio'
|
5
|
+
rescue LoadError
|
6
|
+
puts "Install the multipart-post gem."
|
7
|
+
raise
|
8
|
+
end
|
9
|
+
|
10
|
+
# Auto-load multipart-post gem on first request.
|
11
|
+
module Faraday
|
12
|
+
CompositeReadIO = ::CompositeReadIO
|
13
|
+
UploadIO = ::UploadIO
|
14
|
+
Parts = ::Parts
|
15
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
module Faraday
|
3
|
+
module Utils
|
4
|
+
include Rack::Utils
|
5
|
+
|
6
|
+
extend Rack::Utils
|
7
|
+
extend self
|
8
|
+
|
9
|
+
HEADERS = Hash.new do |h, k|
|
10
|
+
if k.respond_to?(:to_str)
|
11
|
+
k
|
12
|
+
else
|
13
|
+
k.to_s.split('_'). # :user_agent => %w(user agent)
|
14
|
+
each { |w| w.capitalize! }. # => %w(User Agent)
|
15
|
+
join('-') # => "User-Agent"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
HEADERS.merge! :etag => "ETag"
|
20
|
+
HEADERS.values.each { |v| v.freeze }
|
21
|
+
|
22
|
+
# Make Rack::Utils build_query method public.
|
23
|
+
public :build_query
|
24
|
+
|
25
|
+
# Be sure to URI escape '+' symbols to %2B. Otherwise, they get interpreted
|
26
|
+
# as spaces.
|
27
|
+
def escape(s)
|
28
|
+
s.to_s.gsub(/([^a-zA-Z0-9_.-]+)/n) do
|
29
|
+
'%' << $1.unpack('H2'*bytesize($1)).join('%').tap { |c| c.upcase! }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Turns param keys into strings
|
34
|
+
def merge_params(existing_params, new_params)
|
35
|
+
new_params.each do |key, value|
|
36
|
+
existing_params[key.to_s] = value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Turns headers keys and values into strings. Look up symbol keys in the
|
41
|
+
# the HEADERS hash.
|
42
|
+
#
|
43
|
+
# h = merge_headers(HeaderHash.new, :content_type => 'text/plain')
|
44
|
+
# h['Content-Type'] # = 'text/plain'
|
45
|
+
#
|
46
|
+
def merge_headers(existing_headers, new_headers)
|
47
|
+
new_headers.each do |key, value|
|
48
|
+
existing_headers[HEADERS[key]] = value.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Receives a URL and returns just the path with the query string sorted.
|
53
|
+
def normalize_path(url)
|
54
|
+
(url.path != "" ? url.path : "/") +
|
55
|
+
(url.query ? "?#{sort_query_params(url.query)}" : "")
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def sort_query_params(query)
|
61
|
+
query.split('&').sort.join('&')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/test/adapters/live_test.rb
CHANGED
@@ -3,7 +3,10 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
|
|
3
3
|
if Faraday::TestCase::LIVE_SERVER
|
4
4
|
module Adapters
|
5
5
|
class LiveTest < Faraday::TestCase
|
6
|
-
|
6
|
+
loaded_adapters = Faraday::Adapter.all_loaded_constants
|
7
|
+
loaded_adapters -= [Faraday::Adapter::ActionDispatch]
|
8
|
+
loaded_adapters << :default
|
9
|
+
loaded_adapters.each do |adapter|
|
7
10
|
define_method "test_#{adapter}_GET_retrieves_the_response_body" do
|
8
11
|
assert_equal 'hello world', create_connection(adapter).get('hello_world').body
|
9
12
|
end
|
@@ -39,6 +42,15 @@ if Faraday::TestCase::LIVE_SERVER
|
|
39
42
|
assert_equal 'text/html', create_connection(adapter).post('echo_name').headers['content-type']
|
40
43
|
end
|
41
44
|
|
45
|
+
define_method "test_#{adapter}_POST_sends_files" do
|
46
|
+
name = File.join(File.dirname(__FILE__), '..', 'live_server.rb')
|
47
|
+
resp = create_connection(adapter).post do |req|
|
48
|
+
req.url 'file'
|
49
|
+
req.body = {'uploaded_file' => Faraday::UploadIO.new(name, 'text/x-ruby')}
|
50
|
+
end
|
51
|
+
assert_equal "file live_server.rb text/x-ruby", resp.body
|
52
|
+
end
|
53
|
+
|
42
54
|
# http://github.com/toland/patron/issues/#issue/9
|
43
55
|
if ENV['FORCE'] || adapter != Faraday::Adapter::Patron
|
44
56
|
define_method "test_#{adapter}_PUT_send_url_encoded_params" do
|
@@ -62,22 +74,19 @@ if Faraday::TestCase::LIVE_SERVER
|
|
62
74
|
end
|
63
75
|
end
|
64
76
|
|
65
|
-
#
|
66
|
-
|
67
|
-
|
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']
|
77
|
+
define_method "test_#{adapter}_HEAD_send_url_encoded_params" do
|
78
|
+
resp = create_connection(adapter).head do |req|
|
79
|
+
req.url 'hello', 'name' => 'zack'
|
72
80
|
end
|
81
|
+
assert_equal 'text/html', resp.headers['content-type']
|
82
|
+
end
|
73
83
|
|
74
|
-
|
75
|
-
|
76
|
-
|
84
|
+
define_method "test_#{adapter}_HEAD_retrieves_no_response_body" do
|
85
|
+
assert_equal '', create_connection(adapter).head('hello_world').body.to_s
|
86
|
+
end
|
77
87
|
|
78
|
-
|
79
|
-
|
80
|
-
end
|
88
|
+
define_method "test_#{adapter}_HEAD_retrieves_the_response_headers" do
|
89
|
+
assert_equal 'text/html', create_connection(adapter).head('hello_world').headers['content-type']
|
81
90
|
end
|
82
91
|
|
83
92
|
define_method "test_#{adapter}_DELETE_retrieves_the_response_headers" do
|
@@ -95,7 +104,7 @@ if Faraday::TestCase::LIVE_SERVER
|
|
95
104
|
assert !connection.in_parallel?
|
96
105
|
assert_equal 'hello world', connection.get('hello_world').body
|
97
106
|
end
|
98
|
-
|
107
|
+
|
99
108
|
define_method "test_#{adapter}_async_requests_uses_parallel_manager_to_run_multiple_json_requests" do
|
100
109
|
resp1, resp2 = nil, nil
|
101
110
|
|