faraday 0.7.6 → 0.8.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -4
- data/README.md +148 -131
- data/Rakefile +12 -60
- data/faraday.gemspec +11 -32
- data/lib/faraday.rb +59 -12
- data/lib/faraday/adapter.rb +17 -1
- data/lib/faraday/adapter/em_http.rb +204 -0
- data/lib/faraday/adapter/em_synchrony.rb +66 -16
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
- data/lib/faraday/adapter/net_http.rb +1 -1
- data/lib/faraday/adapter/test.rb +13 -6
- data/lib/faraday/adapter/typhoeus.rb +64 -29
- data/lib/faraday/builder.rb +12 -17
- data/lib/faraday/connection.rb +131 -102
- data/lib/faraday/middleware.rb +17 -9
- data/lib/faraday/request.rb +40 -25
- data/lib/faraday/request/basic_authentication.rb +17 -0
- data/lib/faraday/request/retry.rb +21 -0
- data/lib/faraday/request/token_authentication.rb +21 -0
- data/lib/faraday/response.rb +2 -1
- data/lib/faraday/utils.rb +122 -18
- data/test/adapters/live_test.rb +35 -30
- data/test/adapters/logger_test.rb +2 -2
- data/test/adapters/typhoeus_test.rb +1 -1
- data/test/authentication_middleware_test.rb +48 -0
- data/test/connection_test.rb +171 -83
- data/test/env_test.rb +28 -3
- data/test/helper.rb +1 -1
- data/test/middleware/retry_test.rb +25 -0
- data/test/middleware_stack_test.rb +56 -2
- data/test/request_middleware_test.rb +2 -47
- data/test/response_middleware_test.rb +4 -4
- metadata +25 -39
- data/lib/faraday/request/json.rb +0 -35
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source '
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
group :development do
|
4
4
|
gem 'sinatra', '~> 1.2'
|
@@ -14,9 +14,6 @@ end
|
|
14
14
|
platforms :ruby do
|
15
15
|
gem 'patron', '~> 0.4'
|
16
16
|
gem 'typhoeus', '~> 0.3'
|
17
|
-
# ActiveSupport::JSON will be used in ruby 1.8 and Yajl in 1.9; this is to test against both adapters
|
18
|
-
gem 'activesupport', '~> 2.3', :require => nil, :platforms => [:ruby_18, :jruby]
|
19
|
-
gem 'yajl-ruby', '~> 1.0', :require => 'yajl', :platforms => :ruby_19
|
20
17
|
end
|
21
18
|
|
22
19
|
platforms :jruby do
|
data/README.md
CHANGED
@@ -1,177 +1,195 @@
|
|
1
|
-
faraday
|
2
|
-
|
3
|
-
Modular HTTP client library using middleware heavily inspired by Rack.
|
1
|
+
# faraday [![Build Status](https://secure.travis-ci.org/technoweenie/faraday.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/technoweenie/faraday.png?travis)][gemnasium]
|
2
|
+
Modular HTTP client library that uses middleware. Heavily inspired by Rack.
|
4
3
|
|
5
|
-
|
4
|
+
[travis]: http://travis-ci.org/technoweenie/faraday
|
5
|
+
[gemnasium]: https://gemnasium.com/technoweenie/faraday
|
6
6
|
|
7
|
-
Usage
|
8
|
-
-----
|
9
|
-
conn = Faraday.new(:url => 'http://sushi.com') do |builder|
|
10
|
-
builder.use Faraday::Request::UrlEncoded # convert request params as "www-form-urlencoded"
|
11
|
-
builder.use Faraday::Request::JSON # encode request params as json
|
12
|
-
builder.use Faraday::Response::Logger # log the request to STDOUT
|
13
|
-
builder.use Faraday::Adapter::NetHttp # make http requests with Net::HTTP
|
7
|
+
## <a name="usage"></a>Usage
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
9
|
+
```ruby
|
10
|
+
conn = Faraday.new(:url => 'http://sushi.com') do |builder|
|
11
|
+
builder.use Faraday::Request::UrlEncoded # convert request params as "www-form-urlencoded"
|
12
|
+
builder.use Faraday::Response::Logger # log the request to STDOUT
|
13
|
+
builder.use Faraday::Adapter::NetHttp # make http requests with Net::HTTP
|
21
14
|
|
22
|
-
|
15
|
+
# or, use shortcuts:
|
16
|
+
builder.request :url_encoded
|
17
|
+
builder.response :logger
|
18
|
+
builder.adapter :net_http
|
19
|
+
end
|
23
20
|
|
24
|
-
|
25
|
-
response.body
|
21
|
+
## GET ##
|
26
22
|
|
27
|
-
|
23
|
+
response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
|
24
|
+
response.body
|
28
25
|
|
29
|
-
|
30
|
-
req.url '/search', :page => 2
|
31
|
-
req.params['limit'] = 100
|
32
|
-
end
|
26
|
+
conn.get '/nigiri', 'X-Awesome' => true # custom request header
|
33
27
|
|
34
|
-
|
28
|
+
conn.get do |req| # GET http://sushi.com/search?page=2&limit=100
|
29
|
+
req.url '/search', :page => 2
|
30
|
+
req.params['limit'] = 100
|
31
|
+
end
|
35
32
|
|
36
|
-
|
33
|
+
## POST ##
|
37
34
|
|
38
|
-
|
39
|
-
conn.post '/nigiri', payload, 'Content-Type' => 'application/json'
|
35
|
+
conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
# post payload as JSON instead of "www-form-urlencoded" encoding:
|
38
|
+
conn.post do |req|
|
39
|
+
req.url '/nigiri'
|
40
|
+
req.headers['Content-Type'] = 'application/json'
|
41
|
+
req.body = '{ "name": "Unagi" }'
|
42
|
+
end
|
43
|
+
|
44
|
+
## Options ##
|
45
|
+
|
46
|
+
conn.get do |req|
|
47
|
+
req.url '/search'
|
48
|
+
req.options = {
|
49
|
+
:timeout => 5, # open/read timeout Integer in seconds
|
50
|
+
:open_timeout => 2, # read timeout Integer in seconds
|
51
|
+
:proxy => {
|
52
|
+
:uri => "http://example.org/", # proxy server URI
|
53
|
+
:user => "me", # proxy server username
|
54
|
+
:password => "test123" # proxy server password
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
```
|
47
59
|
|
48
60
|
If you're ready to roll with just the bare minimum:
|
49
61
|
|
50
|
-
|
51
|
-
|
62
|
+
```ruby
|
63
|
+
# default stack (net/http), no extra middleware:
|
64
|
+
response = Faraday.get 'http://sushi.com/nigiri/sake.json'
|
65
|
+
```
|
52
66
|
|
53
|
-
Advanced middleware usage
|
54
|
-
-------------------------
|
67
|
+
## Advanced middleware usage
|
55
68
|
The order in which middleware is stacked is important. Like with Rack, the first middleware on the list wraps all others, while the last middleware is the innermost one, so that's usually the adapter.
|
56
69
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
70
|
+
```ruby
|
71
|
+
conn = Faraday.new(:url => 'http://sushi.com') do |builder|
|
72
|
+
# POST/PUT params encoders:
|
73
|
+
builder.request :multipart
|
74
|
+
builder.request :url_encoded
|
62
75
|
|
63
|
-
|
64
|
-
|
76
|
+
builder.adapter :net_http
|
77
|
+
end
|
78
|
+
```
|
65
79
|
|
66
80
|
This request middleware setup affects POST/PUT requests in the following way:
|
67
81
|
|
68
82
|
1. `Request::Multipart` checks for files in the payload, otherwise leaves everything untouched;
|
69
83
|
2. `Request::UrlEncoded` encodes as "application/x-www-form-urlencoded" if not already encoded or of another type
|
70
|
-
2. `Request::JSON` encodes as "application/json" if not already encoded or of another type
|
71
84
|
|
72
|
-
|
85
|
+
Swapping middleware means giving the other priority. Specifying the "Content-Type" for the request is explicitly stating which middleware should process it.
|
73
86
|
|
74
87
|
Examples:
|
75
88
|
|
76
|
-
|
89
|
+
```ruby
|
90
|
+
payload = { :name => 'Maguro' }
|
77
91
|
|
78
|
-
|
79
|
-
|
92
|
+
# uploading a file:
|
93
|
+
payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
|
80
94
|
|
81
|
-
|
82
|
-
|
95
|
+
# "Multipart" middleware detects files and encodes with "multipart/form-data":
|
96
|
+
conn.put '/profile', payload
|
97
|
+
```
|
83
98
|
|
84
|
-
|
85
|
-
conn.put '/profile', payload
|
86
|
-
|
87
|
-
Writing middleware
|
88
|
-
------------------
|
99
|
+
## Writing middleware
|
89
100
|
Middleware are classes that respond to `call()`. They wrap the request/response cycle.
|
90
101
|
|
91
|
-
|
92
|
-
|
102
|
+
```ruby
|
103
|
+
def call(env)
|
104
|
+
# do something with the request
|
93
105
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
106
|
+
@app.call(env).on_complete do
|
107
|
+
# do something with the response
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
98
111
|
|
99
112
|
It's important to do all processing of the response only in the `on_complete` block. This enables middleware to work in parallel mode where requests are asynchronous.
|
100
113
|
|
101
114
|
The `env` is a hash with symbol keys that contains info about the request and, later, response. Some keys are:
|
102
115
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
116
|
+
```
|
117
|
+
# request phase
|
118
|
+
:method - :get, :post, ...
|
119
|
+
:url - URI for the current request; also contains GET parameters
|
120
|
+
:body - POST parameters for :post/:put requests
|
121
|
+
:request_headers
|
122
|
+
|
123
|
+
# response phase
|
124
|
+
:status - HTTP response status code, such as 200
|
125
|
+
:body - the response body
|
126
|
+
:response_headers
|
127
|
+
```
|
128
|
+
|
129
|
+
## <a name="testing"></a>Testing
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
# It's possible to define stubbed request outside a test adapter block.
|
133
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
134
|
+
stub.get('/tamago') { [200, {}, 'egg'] }
|
135
|
+
end
|
136
|
+
|
137
|
+
# You can pass stubbed request to the test adapter or define them in a block
|
138
|
+
# or a combination of the two.
|
139
|
+
test = Faraday.new do |builder|
|
140
|
+
builder.adapter :test, stubs do |stub|
|
141
|
+
stub.get('/ebi') {[ 200, {}, 'shrimp' ]}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# It's also possible to stub additional requests after the connection has
|
146
|
+
# been initialized. This is useful for testing.
|
147
|
+
stubs.get('/uni') {[ 200, {}, 'urchin' ]}
|
148
|
+
|
149
|
+
resp = test.get '/tamago'
|
150
|
+
resp.body # => 'egg'
|
151
|
+
resp = test.get '/ebi'
|
152
|
+
resp.body # => 'shrimp'
|
153
|
+
resp = test.get '/uni'
|
154
|
+
resp.body # => 'urchin'
|
155
|
+
resp = test.get '/else' #=> raises "no such stub" error
|
156
|
+
|
157
|
+
# If you like, you can treat your stubs as mocks by verifying that all of
|
158
|
+
# the stubbed calls were made. NOTE that this feature is still fairly
|
159
|
+
# experimental: It will not verify the order or count of any stub, only that
|
160
|
+
# it was called once during the course of the test.
|
161
|
+
stubs.verify_stubbed_calls
|
162
|
+
```
|
163
|
+
|
164
|
+
## <a name="todo"></a>TODO
|
149
165
|
* support streaming requests/responses
|
150
166
|
* better stubbing API
|
151
|
-
* Support timeouts
|
152
167
|
* Add curb, em-http, fast_http
|
153
168
|
|
154
|
-
Note on Patches/Pull Requests
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
Supported
|
165
|
-
|
166
|
-
This library aims to support and is [tested
|
167
|
-
against](http://travis-ci.org/technoweenie/faraday) the following Ruby
|
169
|
+
## <a name="pulls"></a>Note on Patches/Pull Requests
|
170
|
+
1. Fork the project.
|
171
|
+
2. Make your feature addition or bug fix.
|
172
|
+
3. Add tests for it. This is important so I don't break it in a future version
|
173
|
+
unintentionally.
|
174
|
+
4. Commit, do not mess with rakefile, version, or history. (if you want to have
|
175
|
+
your own version, that is fine but bump version in a commit by itself I can
|
176
|
+
ignore when I pull)
|
177
|
+
5. Send me a pull request. Bonus points for topic branches.
|
178
|
+
|
179
|
+
## <a name="versions"></a>Supported Ruby Versions
|
180
|
+
This library aims to support and is [tested against][travis] the following Ruby
|
168
181
|
implementations:
|
169
182
|
|
170
183
|
* Ruby 1.8.7
|
171
|
-
* Ruby 1.9.1
|
172
184
|
* Ruby 1.9.2
|
173
|
-
*
|
174
|
-
* [
|
185
|
+
* Ruby 1.9.3
|
186
|
+
* JRuby[]
|
187
|
+
* [Rubinius][]
|
188
|
+
* [Ruby Enterprise Edition][ree]
|
189
|
+
|
190
|
+
[jruby]: http://jruby.org/
|
191
|
+
[rubinius]: http://rubini.us/
|
192
|
+
[ree]: http://www.rubyenterpriseedition.com/
|
175
193
|
|
176
194
|
If something doesn't work on one of these interpreters, it should be considered
|
177
195
|
a bug.
|
@@ -187,8 +205,7 @@ implementation, you will be personally responsible for providing patches in a
|
|
187
205
|
timely fashion. If critical issues for a particular implementation exist at the
|
188
206
|
time of a major release, support for that Ruby version may be dropped.
|
189
207
|
|
190
|
-
Copyright
|
191
|
-
|
192
|
-
Copyright (c) 2009-2011 rick, hobson. See [LICENSE][license] for details.
|
208
|
+
## <a name="copyright"></a>Copyright
|
209
|
+
Copyright (c) 2009 rick olson, zack hobson. See [LICENSE][] for details.
|
193
210
|
|
194
211
|
[license]: https://github.com/technoweenie/faraday/blob/master/LICENSE.md
|
data/Rakefile
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
|
-
|
3
1
|
require 'date'
|
2
|
+
require 'rake/testtask'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
#############################################################################
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
## helper functions
|
10
7
|
|
11
8
|
def name
|
12
9
|
@name ||= Dir['*.gemspec'].first.split('.').first
|
@@ -17,14 +14,6 @@ def version
|
|
17
14
|
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
18
15
|
end
|
19
16
|
|
20
|
-
def date
|
21
|
-
Date.today.to_s
|
22
|
-
end
|
23
|
-
|
24
|
-
def rubyforge_project
|
25
|
-
name
|
26
|
-
end
|
27
|
-
|
28
17
|
def gemspec_file
|
29
18
|
"#{name}.gemspec"
|
30
19
|
end
|
@@ -37,26 +26,17 @@ def replace_header(head, header_name)
|
|
37
26
|
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
38
27
|
end
|
39
28
|
|
40
|
-
|
41
|
-
#
|
42
|
-
# Standard tasks
|
43
|
-
#
|
44
|
-
#############################################################################
|
29
|
+
## standard tasks
|
45
30
|
|
46
|
-
task :default => :test
|
47
|
-
|
48
|
-
require 'rake/testtask'
|
49
31
|
Rake::TestTask.new(:test) do |test|
|
50
32
|
test.libs << 'lib' << 'test'
|
51
33
|
test.pattern = 'test/**/*_test.rb'
|
52
34
|
test.verbose = true
|
53
35
|
end
|
54
36
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
task :"test:live" do
|
59
|
-
ENV['LIVE'] = TEST_SERVER
|
37
|
+
desc "Run tests including live tests against a local server on port 4567"
|
38
|
+
task :"test:local" do
|
39
|
+
ENV['LIVE'] = '1'
|
60
40
|
Rake::Task[:test].invoke
|
61
41
|
end
|
62
42
|
|
@@ -65,25 +45,13 @@ task :console do
|
|
65
45
|
sh "irb -rubygems -r ./lib/#{name}.rb"
|
66
46
|
end
|
67
47
|
|
68
|
-
|
69
|
-
#
|
70
|
-
# Custom tasks (add your own tasks here)
|
71
|
-
#
|
72
|
-
#############################################################################
|
73
|
-
|
48
|
+
## release management tasks
|
74
49
|
|
75
|
-
|
76
|
-
#############################################################################
|
77
|
-
#
|
78
|
-
# Packaging tasks
|
79
|
-
#
|
80
|
-
#############################################################################
|
81
|
-
|
82
|
-
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
50
|
+
desc "Commit, create tag v#{version} and build and push #{gem_file} to Rubygems"
|
83
51
|
task :release => :build do
|
84
52
|
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
85
53
|
sh "git tag v#{version}"
|
86
|
-
sh "git push
|
54
|
+
sh "git push"
|
87
55
|
sh "git push origin v#{version}"
|
88
56
|
sh "gem push pkg/#{gem_file}"
|
89
57
|
end
|
@@ -96,7 +64,7 @@ task :build => :gemspec do
|
|
96
64
|
end
|
97
65
|
|
98
66
|
desc "Generate #{gemspec_file}"
|
99
|
-
task :gemspec
|
67
|
+
task :gemspec do
|
100
68
|
# read spec file and split out manifest section
|
101
69
|
spec = File.read(gemspec_file)
|
102
70
|
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
@@ -104,9 +72,6 @@ task :gemspec => :validate do
|
|
104
72
|
# replace name version and date
|
105
73
|
replace_header(head, :name)
|
106
74
|
replace_header(head, :version)
|
107
|
-
replace_header(head, :date)
|
108
|
-
#comment this out if your rubyforge_project has a different name
|
109
|
-
replace_header(head, :rubyforge_project)
|
110
75
|
|
111
76
|
# determine file list from git ls-files
|
112
77
|
files = `git ls-files`.
|
@@ -123,16 +88,3 @@ task :gemspec => :validate do
|
|
123
88
|
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
124
89
|
puts "Updated #{gemspec_file}"
|
125
90
|
end
|
126
|
-
|
127
|
-
desc "Validate #{gemspec_file}"
|
128
|
-
task :validate do
|
129
|
-
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
130
|
-
unless libfiles.empty?
|
131
|
-
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
132
|
-
exit!
|
133
|
-
end
|
134
|
-
unless Dir['VERSION*'].empty?
|
135
|
-
puts "A `VERSION` file at root level violates Gem best practices."
|
136
|
-
exit!
|
137
|
-
end
|
138
|
-
end
|