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.
Files changed (39) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +48 -61
  3. data/Rakefile +3 -1
  4. data/VERSION +1 -1
  5. data/faraday.gemspec +31 -14
  6. data/lib/faraday.rb +33 -26
  7. data/lib/faraday/adapter/net_http.rb +17 -31
  8. data/lib/faraday/adapter/patron.rb +33 -0
  9. data/lib/faraday/adapter/test.rb +96 -0
  10. data/lib/faraday/adapter/typhoeus.rb +43 -59
  11. data/lib/faraday/builder.rb +57 -0
  12. data/lib/faraday/connection.rb +112 -105
  13. data/lib/faraday/middleware.rb +54 -0
  14. data/lib/faraday/request.rb +77 -0
  15. data/lib/faraday/request/active_support_json.rb +20 -0
  16. data/lib/faraday/request/yajl.rb +18 -0
  17. data/lib/faraday/response.rb +41 -26
  18. data/lib/faraday/response/active_support_json.rb +22 -0
  19. data/lib/faraday/response/yajl.rb +20 -0
  20. data/test/adapters/live_test.rb +157 -0
  21. data/test/adapters/test_middleware_test.rb +28 -0
  22. data/test/adapters/typhoeus_test.rb +28 -0
  23. data/test/connection_app_test.rb +49 -0
  24. data/test/connection_test.rb +47 -18
  25. data/test/env_test.rb +35 -0
  26. data/test/helper.rb +5 -2
  27. data/test/live_server.rb +2 -15
  28. data/test/request_middleware_test.rb +19 -0
  29. data/test/response_middleware_test.rb +21 -0
  30. metadata +46 -16
  31. data/lib/faraday/adapter/mock_request.rb +0 -120
  32. data/lib/faraday/loadable.rb +0 -13
  33. data/lib/faraday/request/post_request.rb +0 -30
  34. data/lib/faraday/request/yajl_request.rb +0 -27
  35. data/lib/faraday/response/yajl_response.rb +0 -35
  36. data/lib/faraday/test_connection.rb +0 -5
  37. data/test/adapter/typhoeus_test.rb +0 -26
  38. data/test/adapter_test.rb +0 -118
  39. data/test/response_test.rb +0 -34
@@ -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,77 @@
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
+ def to_env_hash(connection, request_method)
58
+ env_headers = connection.headers.dup
59
+ env_params = connection.params.dup
60
+ connection.merge_headers env_headers, headers
61
+ connection.merge_params env_params, params
62
+
63
+ { :method => request_method,
64
+ :body => body,
65
+ :url => connection.build_url(path, env_params),
66
+ :request_headers => env_headers,
67
+ :parallel_manager => connection.parallel_manager,
68
+ :response => Response.new}
69
+ end
70
+
71
+ def run(connection, request_method)
72
+ app = connection.to_app
73
+ env = to_env_hash(connection, request_method)
74
+ app.call(env)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ module Faraday
2
+ class Request::ActiveSupportJson < Faraday::Middleware
3
+ begin
4
+ if !defined?(ActiveSupport::JSON)
5
+ require 'active_support'
6
+ end
7
+
8
+ rescue LoadError => e
9
+ self.load_error = e
10
+ end
11
+
12
+ def call(env)
13
+ env[:request_headers]['Content-Type'] = 'application/json'
14
+ if env[:body] && !env[:body].respond_to?(:to_str)
15
+ env[:body] = ActiveSupport::JSON.encode env[:body]
16
+ end
17
+ @app.call env
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module Faraday
2
+ class Request::Yajl < Faraday::Middleware
3
+ begin
4
+ require 'yajl'
5
+
6
+ rescue LoadError => 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
@@ -1,38 +1,53 @@
1
1
  module Faraday
2
- class Response < Struct.new(:headers, :body)
3
- extend Loadable
2
+ class Response
3
+ class Middleware < Faraday::Middleware
4
+ self.load_error = :abstract
4
5
 
5
- extend AutoloadHelper
6
- autoload_all 'faraday/response',
7
- :YajlResponse => 'yajl_response'
8
-
9
- def initialize(headers = nil, body = nil)
10
- super(headers || {}, body)
11
- if block_given?
12
- yield self
13
- processed!
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)
14
13
  end
15
- end
16
14
 
17
- # TODO: process is a funky name. change it
18
- # processes a chunk of the streamed body.
19
- def process(chunk)
20
- if !body
21
- self.body = []
15
+ def call(env)
16
+ self.class.register_on_complete(env)
17
+ @app.call env
22
18
  end
23
- body << chunk
24
19
  end
25
20
 
26
- # Assume the given content is the full body, and not streamed.
27
- def process!(full_body)
28
- process(full_body)
29
- processed!
21
+ extend AutoloadHelper
22
+
23
+ autoload_all 'faraday/response',
24
+ :Yajl => 'yajl',
25
+ :ActiveSupportJson => 'active_support_json'
26
+
27
+ register_lookup_modules \
28
+ :yajl => :Yajl,
29
+ :activesupport_json => :ActiveSupportJson,
30
+ :rails_json => :ActiveSupportJson,
31
+ :active_support_json => :ActiveSupportJson
32
+ attr_accessor :status, :headers, :body
33
+
34
+ def initialize
35
+ @status, @headers, @body = nil, nil, nil
36
+ @on_complete_callbacks = []
37
+ end
38
+
39
+ def on_complete(&block)
40
+ @on_complete_callbacks << block
41
+ end
42
+
43
+ def finish(env)
44
+ @on_complete_callbacks.each { |c| c.call(env) }
45
+ @status, @headers, @body = env[:status], env[:response_headers], env[:body]
46
+ self
30
47
  end
31
48
 
32
- # Signals the end of streamed content. Do whatever you need to clean up
33
- # the streamed body.
34
- def processed!
35
- self.body = body.join if body.respond_to?(:join)
49
+ def success?
50
+ status == 200
36
51
  end
37
52
  end
38
53
  end
@@ -0,0 +1,22 @@
1
+ module Faraday
2
+ class Response::ActiveSupportJson < Response::Middleware
3
+ begin
4
+ if !defined?(ActiveSupport::JSON)
5
+ require 'active_support'
6
+ end
7
+
8
+ def self.register_on_complete(env)
9
+ env[:response].on_complete do |finished_env|
10
+ finished_env[:body] = ActiveSupport::JSON.decode(finished_env[:body])
11
+ end
12
+ end
13
+ rescue LoadError => e
14
+ self.load_error = e
15
+ end
16
+
17
+ def initialize(app)
18
+ super
19
+ @parser = nil
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
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] = Yajl::Parser.parse(finished_env[:body])
9
+ end
10
+ end
11
+ rescue LoadError => e
12
+ self.load_error = e
13
+ end
14
+
15
+ def initialize(app)
16
+ super
17
+ @parser = nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,157 @@
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.each do |adapter|
7
+ describe "with #{adapter} adapter" do
8
+ before do
9
+ @connection = Faraday::Connection.new LIVE_SERVER do
10
+ use adapter
11
+ end
12
+ end
13
+
14
+ describe "#get" do
15
+ it "raises on 404" do
16
+ assert_raise(Faraday::Error::ResourceNotFound) { @connection.get('/nothing') }
17
+ end
18
+
19
+ it "retrieves the response body" do
20
+ assert_equal 'hello world', @connection.get('hello_world').body
21
+ end
22
+
23
+ it "send url-encoded params" do
24
+ resp = @connection.get do |req|
25
+ req.url 'hello', 'name' => 'zack'
26
+ end
27
+ assert_equal('hello zack', resp.body)
28
+ end
29
+
30
+ it "retrieves the response headers" do
31
+ assert_equal 'text/html', @connection.get('hello_world').headers['content-type']
32
+ end
33
+ end
34
+
35
+ describe "#post" do
36
+ it "raises on 404" do
37
+ assert_raise(Faraday::Error::ResourceNotFound) { @connection.post('/nothing') }
38
+ end
39
+
40
+ it "send url-encoded params" do
41
+ resp = @connection.post do |req|
42
+ req.url 'echo_name'
43
+ req.body = {'name' => 'zack'}
44
+ end
45
+ assert_equal %("zack"), resp.body
46
+ end
47
+
48
+ it "send url-encoded nested params" do
49
+ resp = @connection.post do |req|
50
+ req.url 'echo_name'
51
+ req.body = {'name' => {'first' => 'zack'}}
52
+ end
53
+ assert_equal %({"first"=>"zack"}), resp.body
54
+ end
55
+
56
+ it "retrieves the response headers" do
57
+ assert_equal 'text/html', @connection.post('echo_name').headers['content-type']
58
+ end
59
+ end
60
+
61
+ # http://github.com/toland/patron/issues/#issue/9
62
+ if ENV['FORCE'] || adapter != Faraday::Adapter::Patron
63
+ describe "#put" do
64
+ it "raises on 404" do
65
+ assert_raise(Faraday::Error::ResourceNotFound) { @connection.put('/nothing') }
66
+ end
67
+
68
+ it "send url-encoded params" do
69
+ resp = @connection.put do |req|
70
+ req.url 'echo_name'
71
+ req.body = {'name' => 'zack'}
72
+ end
73
+ assert_equal %("zack"), resp.body
74
+ end
75
+
76
+ it "send url-encoded nested params" do
77
+ resp = @connection.put do |req|
78
+ req.url 'echo_name'
79
+ req.body = {'name' => {'first' => 'zack'}}
80
+ end
81
+ assert_equal %({"first"=>"zack"}), resp.body
82
+ end
83
+
84
+ it "retrieves the response headers" do
85
+ assert_equal 'text/html', @connection.put('echo_name').headers['content-type']
86
+ end
87
+ end
88
+ end
89
+
90
+ # http://github.com/pauldix/typhoeus/issues#issue/7
91
+ if ENV['FORCE'] || adapter != Faraday::Adapter::Typhoeus
92
+ describe "#head" do
93
+ it "raises on 404" do
94
+ assert_raise(Faraday::Error::ResourceNotFound) { @connection.head('/nothing') }
95
+ end
96
+
97
+ it "send url-encoded params" do
98
+ resp = @connection.head do |req|
99
+ req.url 'hello', 'name' => 'zack'
100
+ end
101
+ assert_equal 'text/html', resp.headers['content-type']
102
+ end
103
+
104
+ it "retrieves no response body" do
105
+ assert_equal '', @connection.head('hello_world').body.to_s
106
+ end
107
+
108
+ it "retrieves the response headers" do
109
+ assert_equal 'text/html', @connection.head('hello_world').headers['content-type']
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#delete" do
115
+ it "raises on 404" do
116
+ assert_raise(Faraday::Error::ResourceNotFound) { @connection.delete('/nothing') }
117
+ end
118
+
119
+ it "retrieves the response headers" do
120
+ assert_equal 'text/html', @connection.delete('delete_with_json').headers['content-type']
121
+ end
122
+
123
+ it "retrieves the body" do
124
+ assert_match /deleted/, @connection.delete('delete_with_json').body
125
+ end
126
+ end
127
+
128
+ describe "async requests" do
129
+ it "clears parallel manager after running a single request" do
130
+ assert !@connection.in_parallel?
131
+ resp = @connection.get('hello_world')
132
+ assert !@connection.in_parallel?
133
+ assert_equal 'hello world', @connection.get('hello_world').body
134
+ end
135
+
136
+ it "uses parallel manager to run multiple json requests" do
137
+ resp1, resp2 = nil, nil
138
+
139
+ @connection.in_parallel(adapter.setup_parallel_manager) do
140
+ resp1 = @connection.get('json')
141
+ resp2 = @connection.get('json')
142
+ if adapter.supports_parallel_requests?
143
+ assert @connection.in_parallel?
144
+ assert_nil resp1.body
145
+ assert_nil resp2.body
146
+ end
147
+ end
148
+ assert !@connection.in_parallel?
149
+ assert_equal '[1,2,3]', resp1.body
150
+ assert_equal '[1,2,3]', resp2.body
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end