faraday 0.1.2 → 0.2.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/LICENSE +1 -1
- data/README.rdoc +48 -61
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/faraday.gemspec +31 -14
- data/lib/faraday.rb +33 -26
- data/lib/faraday/adapter/net_http.rb +17 -31
- data/lib/faraday/adapter/patron.rb +33 -0
- data/lib/faraday/adapter/test.rb +96 -0
- data/lib/faraday/adapter/typhoeus.rb +43 -59
- data/lib/faraday/builder.rb +57 -0
- data/lib/faraday/connection.rb +112 -105
- data/lib/faraday/middleware.rb +54 -0
- data/lib/faraday/request.rb +77 -0
- data/lib/faraday/request/active_support_json.rb +20 -0
- data/lib/faraday/request/yajl.rb +18 -0
- data/lib/faraday/response.rb +41 -26
- data/lib/faraday/response/active_support_json.rb +22 -0
- data/lib/faraday/response/yajl.rb +20 -0
- data/test/adapters/live_test.rb +157 -0
- data/test/adapters/test_middleware_test.rb +28 -0
- data/test/adapters/typhoeus_test.rb +28 -0
- data/test/connection_app_test.rb +49 -0
- data/test/connection_test.rb +47 -18
- data/test/env_test.rb +35 -0
- data/test/helper.rb +5 -2
- data/test/live_server.rb +2 -15
- data/test/request_middleware_test.rb +19 -0
- data/test/response_middleware_test.rb +21 -0
- metadata +46 -16
- data/lib/faraday/adapter/mock_request.rb +0 -120
- data/lib/faraday/loadable.rb +0 -13
- data/lib/faraday/request/post_request.rb +0 -30
- data/lib/faraday/request/yajl_request.rb +0 -27
- data/lib/faraday/response/yajl_response.rb +0 -35
- data/lib/faraday/test_connection.rb +0 -5
- data/test/adapter/typhoeus_test.rb +0 -26
- data/test/adapter_test.rb +0 -118
- data/test/response_test.rb +0 -34
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,79 +1,66 @@
|
|
1
1
|
= faraday
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
Super alpha! Don't use it if you mind throwing away all the code when I change
|
6
|
-
the API on a whim.
|
3
|
+
Modular HTTP client library using middleware heavily inspired by Rack.
|
7
4
|
|
8
5
|
This mess is gonna get raw, like sushi. So, haters to the left.
|
9
6
|
|
10
7
|
== Usage
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# uses Typhoeus, Yajl parsing, performs requests in parallel
|
32
|
-
conn = Faraday::Connection.new("http://sushi.com")
|
33
|
-
conn.extend Faraday::Adapter::Typhoeus
|
34
|
-
conn.response_class = Faraday::Response::YajlResponse
|
35
|
-
resp1, resp2 = nil, nil
|
36
|
-
conn.in_parallel do
|
37
|
-
resp1 = conn.get("/sake.json")
|
38
|
-
resp2 = conn.get("/unagi.json")
|
39
|
-
|
40
|
-
# requests have not been made yet
|
41
|
-
resp1.body # => nil
|
42
|
-
resp2.body # => nil
|
43
|
-
end
|
44
|
-
resp1.body # => {"name": "Sake"}
|
45
|
-
resp2.body # => {"name": "Unagi"}
|
9
|
+
conn = Alice::Connection.new(:url => 'http://sushi.com') do |builder|
|
10
|
+
builder.use Alice::Request::Yajl # convert body to json with Yajl lib
|
11
|
+
builder.use Alice::Adapter::Logger # log the request somewhere?
|
12
|
+
builder.use Alice::Adapter::Typhoeus # make http request with typhoeus
|
13
|
+
builder.use Alice::Response::Yajl # # parse body with yajl
|
14
|
+
|
15
|
+
# or use shortcuts
|
16
|
+
builder.request :yajl # Alice::Request::Yajl
|
17
|
+
builder.adapter :logger # Alice::Adapter::Logger
|
18
|
+
builder.adapter :typhoeus # Alice::Adapter::Typhoeus
|
19
|
+
builder.response :yajl # Alice::Response::Yajl
|
20
|
+
end
|
21
|
+
|
22
|
+
resp1 = conn.get '/nigiri/sake.json'
|
23
|
+
resp2 = conn.post do |req|
|
24
|
+
req.url "/nigiri.json", :page => 2
|
25
|
+
req[:content_type] = 'application/json'
|
26
|
+
req.body = {:name => 'Unagi'}
|
27
|
+
end
|
46
28
|
|
47
29
|
== Testing
|
48
30
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
31
|
+
# It's possible to define stubbed request outside a test adapter block.
|
32
|
+
stubs = Alice::Test::Stubs.new do |stub|
|
33
|
+
stub.get('/tamago') { [200, 'egg', {} }
|
34
|
+
end
|
53
35
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
include Faraday::Adapter::MockRequest
|
36
|
+
# You can pass stubbed request to the test adapter or define them in a block
|
37
|
+
# or a combination of the two.
|
38
|
+
test = Alice::Connection.new do |builder|
|
39
|
+
builder.adapter :test, stubs do |stub|
|
40
|
+
stub.get('/ebi') {[ 200, 'shrimp', {} ]}
|
60
41
|
end
|
42
|
+
end
|
61
43
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
44
|
+
# It's also possible to stub additional requests after the connection has
|
45
|
+
# been initialized. This is useful for testing.
|
46
|
+
stubs.get('/uni') {[ 200, 'urchin', {} ]}
|
47
|
+
|
48
|
+
resp = test.get '/tamago'
|
49
|
+
resp.body # => 'egg'
|
50
|
+
resp = test.get '/ebi'
|
51
|
+
resp.body # => 'shrimp'
|
52
|
+
resp = test.get '/uni'
|
53
|
+
resp.body # => 'urchin'
|
54
|
+
resp = test.get '/else' #=> raises "no such stub" error
|
69
55
|
|
70
56
|
== TODO
|
71
57
|
|
72
|
-
*
|
73
|
-
*
|
74
|
-
*
|
75
|
-
*
|
76
|
-
*
|
58
|
+
* Add curb/em-http support
|
59
|
+
* Add xml parsing
|
60
|
+
* Support timeouts, proxy servers, ssl options
|
61
|
+
* Add streaming requests and responses
|
62
|
+
* Add default middleware load out for common cases
|
63
|
+
* Add symbol => string index for mime types (:json => 'application/json')
|
77
64
|
|
78
65
|
== Note on Patches/Pull Requests
|
79
66
|
|
@@ -87,4 +74,4 @@ connection class:
|
|
87
74
|
|
88
75
|
== Copyright
|
89
76
|
|
90
|
-
Copyright (c) 2009 rick. See LICENSE for details.
|
77
|
+
Copyright (c) 2009-2010 rick, hobson. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -10,6 +10,8 @@ begin
|
|
10
10
|
gem.email = "technoweenie@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/technoweenie/faraday"
|
12
12
|
gem.authors = ["rick"]
|
13
|
+
gem.add_dependency "rack"
|
14
|
+
gem.add_dependency "addressable"
|
13
15
|
end
|
14
16
|
Jeweler::GemcutterTasks.new
|
15
17
|
rescue LoadError
|
@@ -27,7 +29,7 @@ begin
|
|
27
29
|
require 'rcov/rcovtask'
|
28
30
|
Rcov::RcovTask.new do |test|
|
29
31
|
test.libs << 'test'
|
30
|
-
test.pattern = 'test
|
32
|
+
test.pattern = 'test/**/*_test.rb'
|
31
33
|
test.verbose = true
|
32
34
|
end
|
33
35
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/faraday.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{faraday}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["rick"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-12}
|
13
13
|
s.description = %q{HTTP/REST API client library with pluggable components}
|
14
14
|
s.email = %q{technoweenie@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,23 +25,30 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"faraday.gemspec",
|
27
27
|
"lib/faraday.rb",
|
28
|
-
"lib/faraday/adapter/mock_request.rb",
|
29
28
|
"lib/faraday/adapter/net_http.rb",
|
29
|
+
"lib/faraday/adapter/patron.rb",
|
30
|
+
"lib/faraday/adapter/test.rb",
|
30
31
|
"lib/faraday/adapter/typhoeus.rb",
|
32
|
+
"lib/faraday/builder.rb",
|
31
33
|
"lib/faraday/connection.rb",
|
32
34
|
"lib/faraday/error.rb",
|
33
|
-
"lib/faraday/
|
34
|
-
"lib/faraday/request
|
35
|
-
"lib/faraday/request/
|
35
|
+
"lib/faraday/middleware.rb",
|
36
|
+
"lib/faraday/request.rb",
|
37
|
+
"lib/faraday/request/active_support_json.rb",
|
38
|
+
"lib/faraday/request/yajl.rb",
|
36
39
|
"lib/faraday/response.rb",
|
37
|
-
"lib/faraday/response/
|
38
|
-
"lib/faraday/
|
39
|
-
"test/
|
40
|
-
"test/
|
40
|
+
"lib/faraday/response/active_support_json.rb",
|
41
|
+
"lib/faraday/response/yajl.rb",
|
42
|
+
"test/adapters/live_test.rb",
|
43
|
+
"test/adapters/test_middleware_test.rb",
|
44
|
+
"test/adapters/typhoeus_test.rb",
|
45
|
+
"test/connection_app_test.rb",
|
41
46
|
"test/connection_test.rb",
|
47
|
+
"test/env_test.rb",
|
42
48
|
"test/helper.rb",
|
43
49
|
"test/live_server.rb",
|
44
|
-
"test/
|
50
|
+
"test/request_middleware_test.rb",
|
51
|
+
"test/response_middleware_test.rb"
|
45
52
|
]
|
46
53
|
s.homepage = %q{http://github.com/technoweenie/faraday}
|
47
54
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -49,12 +56,16 @@ Gem::Specification.new do |s|
|
|
49
56
|
s.rubygems_version = %q{1.3.5}
|
50
57
|
s.summary = %q{HTTP/REST API client library}
|
51
58
|
s.test_files = [
|
52
|
-
"test/
|
53
|
-
"test/
|
59
|
+
"test/adapters/live_test.rb",
|
60
|
+
"test/adapters/test_middleware_test.rb",
|
61
|
+
"test/adapters/typhoeus_test.rb",
|
62
|
+
"test/connection_app_test.rb",
|
54
63
|
"test/connection_test.rb",
|
64
|
+
"test/env_test.rb",
|
55
65
|
"test/helper.rb",
|
56
66
|
"test/live_server.rb",
|
57
|
-
"test/
|
67
|
+
"test/request_middleware_test.rb",
|
68
|
+
"test/response_middleware_test.rb"
|
58
69
|
]
|
59
70
|
|
60
71
|
if s.respond_to? :specification_version then
|
@@ -62,9 +73,15 @@ Gem::Specification.new do |s|
|
|
62
73
|
s.specification_version = 3
|
63
74
|
|
64
75
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
76
|
+
s.add_runtime_dependency(%q<rack>, [">= 0"])
|
77
|
+
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
65
78
|
else
|
79
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
80
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
66
81
|
end
|
67
82
|
else
|
83
|
+
s.add_dependency(%q<rack>, [">= 0"])
|
84
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
68
85
|
end
|
69
86
|
end
|
70
87
|
|
data/lib/faraday.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
module AutoloadHelper
|
5
|
+
def register_lookup_modules(mods)
|
6
|
+
(@lookup_module_index ||= {}).update(mods)
|
7
|
+
end
|
8
|
+
|
9
|
+
def lookup_module(key)
|
10
|
+
return if !@lookup_module_index
|
11
|
+
const_get @lookup_module_index[key] || key
|
12
|
+
end
|
13
|
+
|
3
14
|
def autoload_all(prefix, options)
|
4
15
|
options.each do |const_name, path|
|
5
16
|
autoload const_name, File.join(prefix, path)
|
@@ -8,45 +19,41 @@ module Faraday
|
|
8
19
|
|
9
20
|
# Loads each autoloaded constant. If thread safety is a concern, wrap
|
10
21
|
# this in a Mutex.
|
11
|
-
def
|
22
|
+
def load_autoloaded_constants
|
12
23
|
constants.each do |const|
|
13
24
|
const_get(const) if autoload?(const)
|
14
25
|
end
|
15
26
|
end
|
27
|
+
|
28
|
+
def all_loaded_constants
|
29
|
+
constants.map { |c| const_get(c) }.select { |a| a.loaded? }
|
30
|
+
end
|
16
31
|
end
|
17
32
|
|
18
33
|
extend AutoloadHelper
|
19
34
|
|
20
35
|
autoload_all 'faraday',
|
21
|
-
:Connection
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
|
27
|
-
module Request
|
28
|
-
extend AutoloadHelper
|
29
|
-
autoload_all 'faraday/request',
|
30
|
-
:YajlRequest => 'yajl_request',
|
31
|
-
:PostRequest => 'post_request'
|
32
|
-
end
|
36
|
+
:Connection => 'connection',
|
37
|
+
:Middleware => 'middleware',
|
38
|
+
:Builder => 'builder',
|
39
|
+
:Request => 'request',
|
40
|
+
:Response => 'response',
|
41
|
+
:Error => 'error'
|
33
42
|
|
34
43
|
module Adapter
|
35
44
|
extend AutoloadHelper
|
36
|
-
autoload_all 'faraday/adapter',
|
37
|
-
:NetHttp
|
38
|
-
:Typhoeus
|
39
|
-
:
|
45
|
+
autoload_all 'faraday/adapter',
|
46
|
+
:NetHttp => 'net_http',
|
47
|
+
:Typhoeus => 'typhoeus',
|
48
|
+
:Patron => 'patron',
|
49
|
+
:Test => 'test'
|
40
50
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
def self.loaded_adapters
|
48
|
-
adapters.map { |c| const_get(c) }.select { |a| a.loaded? }
|
49
|
-
end
|
51
|
+
register_lookup_modules \
|
52
|
+
:test => :Test,
|
53
|
+
:net_http => :NetHttp,
|
54
|
+
:typhoeus => :Typhoeus,
|
55
|
+
:patron => :patron,
|
56
|
+
:net_http => :NetHttp
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
@@ -1,42 +1,28 @@
|
|
1
1
|
require 'net/http'
|
2
|
-
require 'cgi'
|
3
2
|
module Faraday
|
4
3
|
module Adapter
|
5
|
-
|
6
|
-
|
4
|
+
class NetHttp < Middleware
|
5
|
+
def call(env)
|
6
|
+
process_body_for_request(env)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
http_resp = http.send_request(method, path_for(uri), data, request_headers)
|
12
|
-
raise Faraday::Error::ResourceNotFound if http_resp.code == '404'
|
13
|
-
resp.process http_resp.body
|
14
|
-
http_resp.each_header do |key, value|
|
15
|
-
resp.headers[key] = value
|
16
|
-
end
|
17
|
-
end
|
18
|
-
rescue Errno::ECONNREFUSED
|
19
|
-
raise Faraday::Error::ConnectionFailed, "connection refused"
|
20
|
-
end
|
21
|
-
|
22
|
-
def _put(uri, data, request_headers)
|
23
|
-
request = request_class.new(data, request_headers)
|
24
|
-
_perform('PUT', uri, request.body, request.headers)
|
25
|
-
end
|
8
|
+
http = Net::HTTP.new(env[:url].host, env[:url].port)
|
9
|
+
full_path = full_path_for(env[:url].path, env[:url].query, env[:url].fragment)
|
10
|
+
http_resp = http.send_request(env[:method].to_s.upcase, full_path, env[:body], env[:request_headers])
|
26
11
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
12
|
+
resp_headers = {}
|
13
|
+
http_resp.each_header do |key, value|
|
14
|
+
resp_headers[key] = value
|
15
|
+
end
|
31
16
|
|
32
|
-
|
33
|
-
|
34
|
-
|
17
|
+
env.update \
|
18
|
+
:status => http_resp.code.to_i,
|
19
|
+
:response_headers => resp_headers,
|
20
|
+
:body => http_resp.body
|
35
21
|
|
36
|
-
|
37
|
-
|
22
|
+
@app.call env
|
23
|
+
rescue Errno::ECONNREFUSED
|
24
|
+
raise Error::ConnectionFailed, "connection refused"
|
38
25
|
end
|
39
|
-
|
40
26
|
end
|
41
27
|
end
|
42
28
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Faraday
|
2
|
+
module Adapter
|
3
|
+
class Patron < Middleware
|
4
|
+
begin
|
5
|
+
require 'patron'
|
6
|
+
rescue LoadError => e
|
7
|
+
self.load_error = e
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
process_body_for_request(env)
|
12
|
+
|
13
|
+
sess = ::Patron::Session.new
|
14
|
+
args = [env[:method], env[:url].to_s, env[:request_headers]]
|
15
|
+
if Faraday::Connection::METHODS_WITH_BODIES.include?(env[:method])
|
16
|
+
args.insert(2, env[:body].to_s)
|
17
|
+
end
|
18
|
+
resp = sess.send *args
|
19
|
+
|
20
|
+
env.update \
|
21
|
+
:status => resp.status,
|
22
|
+
:response_headers => resp.headers.
|
23
|
+
inject({}) { |memo, (k, v)| memo.update(k.downcase => v) },
|
24
|
+
:body => resp.body
|
25
|
+
env[:response].finish(env)
|
26
|
+
|
27
|
+
@app.call env
|
28
|
+
rescue Errno::ECONNREFUSED
|
29
|
+
raise Error::ConnectionFailed, "connection refused"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Faraday
|
2
|
+
module Adapter
|
3
|
+
# test = Faraday::Connection.new do
|
4
|
+
# use Faraday::Adapter::Test do |stub|
|
5
|
+
# stub.get '/nigiri/sake.json' do
|
6
|
+
# [200, {}, 'hi world']
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# resp = test.get '/nigiri/sake.json'
|
12
|
+
# resp.body # => 'hi world'
|
13
|
+
#
|
14
|
+
class Test < Middleware
|
15
|
+
attr_accessor :stubs
|
16
|
+
|
17
|
+
def self.loaded?() false end
|
18
|
+
|
19
|
+
class Stubs
|
20
|
+
def initialize
|
21
|
+
# {:get => [Stub, Stub]}
|
22
|
+
@stack = {}
|
23
|
+
yield self if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty?
|
27
|
+
@stack.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
def match(request_method, path, body)
|
31
|
+
return false if !@stack.key?(request_method)
|
32
|
+
stub = @stack[request_method].detect { |stub| stub.matches?(path, body) }
|
33
|
+
@stack[request_method].delete stub
|
34
|
+
end
|
35
|
+
|
36
|
+
def get(path, &block)
|
37
|
+
new_stub(:get, path, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def head(path, &block)
|
41
|
+
new_stub(:head, path, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def post(path, body=nil, &block)
|
45
|
+
new_stub(:post, path, body, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def put(path, body=nil, &block)
|
49
|
+
new_stub(:put, path, body, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(path, &block)
|
53
|
+
new_stub(:delete, path, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def new_stub(request_method, path, body=nil, &block)
|
57
|
+
(@stack[request_method] ||= []) << Stub.new(path, body, block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Stub < Struct.new(:path, :body, :block)
|
62
|
+
def matches?(request_path, request_body)
|
63
|
+
request_path == path && request_body == body
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize app, stubs=nil, &block
|
68
|
+
super(app)
|
69
|
+
@stubs = stubs || Stubs.new
|
70
|
+
configure(&block) if block
|
71
|
+
end
|
72
|
+
|
73
|
+
def configure
|
74
|
+
yield stubs
|
75
|
+
end
|
76
|
+
|
77
|
+
def request_uri url
|
78
|
+
(url.path != "" ? url.path : "/") +
|
79
|
+
(url.query ? "?#{url.query}" : "")
|
80
|
+
end
|
81
|
+
|
82
|
+
def call(env)
|
83
|
+
if stub = stubs.match(env[:method], request_uri(env[:url]), env[:body])
|
84
|
+
status, headers, body = stub.block.call(env)
|
85
|
+
env.update \
|
86
|
+
:status => status,
|
87
|
+
:response_headers => headers,
|
88
|
+
:body => body
|
89
|
+
else
|
90
|
+
raise "no stubbed request for #{env[:method]} #{request_uri(env[:url])} #{env[:body]}"
|
91
|
+
end
|
92
|
+
@app.call(env)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|