faraday-stack 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -2
- data/lib/faraday_stack.rb +11 -2
- data/lib/faraday_stack/addressable_patch.rb +13 -11
- data/lib/faraday_stack/caching.rb +3 -6
- data/lib/faraday_stack/response_json.rb +18 -0
- data/test/factory_test.rb +28 -0
- data/test/response_middleware_test.rb +21 -0
- metadata +49 -29
data/README.md
CHANGED
@@ -38,7 +38,9 @@ Awesome example:
|
|
38
38
|
* raises exceptions on 4xx, 5xx responses
|
39
39
|
* follows redirects
|
40
40
|
|
41
|
-
|
41
|
+
To see how the default stack is built, see "[faraday_stack.rb][source]".
|
42
|
+
|
43
|
+
### Optional features:
|
42
44
|
|
43
45
|
* encode POST/PUT bodies as JSON:
|
44
46
|
|
@@ -55,7 +57,14 @@ Optional features:
|
|
55
57
|
:namespace => 'faraday', :expires_in => 3600
|
56
58
|
end
|
57
59
|
|
58
|
-
|
60
|
+
* mount [Rack::Cache][] through `RackCompatible` middleware for HTTP caching of responses
|
61
|
+
|
62
|
+
conn.builder.insert_after FaradayStack::FollowRedirects, FaradayStack::RackCompatible,
|
63
|
+
Rack::Cache::Context,
|
64
|
+
:metastore => "file:/var/cache/rack/meta",
|
65
|
+
:entitystore => "file:/var/cache/rack/body"
|
66
|
+
|
59
67
|
|
60
68
|
[faraday]: https://github.com/technoweenie/faraday
|
61
69
|
[source]: https://github.com/mislav/faraday-stack/blob/master/lib/faraday_stack.rb
|
70
|
+
[rack::cache]: http://rtomayko.github.com/rack-cache/
|
data/lib/faraday_stack.rb
CHANGED
@@ -28,13 +28,22 @@ module FaradayStack
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.build(url = nil, options = {})
|
31
|
-
|
31
|
+
klass = nil
|
32
|
+
if url.is_a?(Hash) then options = url.dup
|
33
|
+
elsif url.is_a?(Class) then klass = url
|
34
|
+
else options = options.merge(:url => url)
|
35
|
+
end
|
36
|
+
|
37
|
+
klass ||= options.delete(:class) || Faraday::Connection
|
38
|
+
|
39
|
+
klass.new(options) do |builder|
|
32
40
|
builder.request :url_encoded
|
33
41
|
builder.request :json
|
34
42
|
yield builder if block_given?
|
35
43
|
builder.use ResponseXML, :content_type => /[+\/]xml$/
|
36
44
|
builder.use ResponseHTML, :content_type => 'text/html'
|
37
|
-
builder.use ResponseJSON, :content_type =>
|
45
|
+
builder.use ResponseJSON, :content_type => /(application|text)\/json/
|
46
|
+
builder.use ResponseJSON::MimeTypeFix, :content_type => /text\/(plain|javascript)/
|
38
47
|
builder.use FollowRedirects
|
39
48
|
builder.response :raise_error
|
40
49
|
builder.adapter Faraday.default_adapter
|
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'addressable/uri'
|
2
2
|
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
# feature-detect the bug
|
4
|
+
unless Addressable::URI.parse('/?a=1&b=2') === '/?b=2&a=1'
|
5
|
+
# fix `normalized_query` by sorting query key-value pairs
|
6
|
+
# (rejected: https://github.com/sporkmonger/addressable/issues/28)
|
7
|
+
class Addressable::URI
|
8
|
+
alias normalized_query_without_ordering_fix normalized_query
|
8
9
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def normalized_query
|
11
|
+
fresh = @normalized_query.nil?
|
12
|
+
query = normalized_query_without_ordering_fix
|
13
|
+
if query && fresh
|
14
|
+
@normalized_query = query.split('&', -1).sort_by {|q| q[0..(q.index('=')||-1)] }.join('&')
|
15
|
+
else
|
16
|
+
query
|
14
17
|
end
|
15
|
-
normalized
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -24,14 +24,11 @@ module FaradayStack
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def cache_key(env)
|
27
|
-
url = env[:url]
|
28
|
-
if params_to_strip.any?
|
29
|
-
url = url.dup
|
27
|
+
url = env[:url].dup
|
28
|
+
if url.query && params_to_strip.any?
|
30
29
|
url.query_values = url.query_values.reject { |k,| params_to_strip.include? k }
|
31
|
-
url.normalize!
|
32
|
-
else
|
33
|
-
url = url.normalize
|
34
30
|
end
|
31
|
+
url.normalize!
|
35
32
|
url.request_uri
|
36
33
|
end
|
37
34
|
|
@@ -28,5 +28,23 @@ module FaradayStack
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
# writes the correct MIME-type if the payload looks like JSON
|
33
|
+
class MimeTypeFix < ResponseMiddleware
|
34
|
+
def on_complete(env)
|
35
|
+
if process_response_type?(response_type(env)) and looks_like_json?(env)
|
36
|
+
old_type = env[:response_headers][CONTENT_TYPE]
|
37
|
+
new_type = 'application/json'
|
38
|
+
new_type << ';' << old_type.split(';', 2).last if old_type.index(';')
|
39
|
+
env[:response_headers][CONTENT_TYPE] = new_type
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
BRACKETS = %w- [ { -
|
44
|
+
|
45
|
+
def looks_like_json?(env)
|
46
|
+
parse_response?(env) and BRACKETS.include? env[:body][0,1]
|
47
|
+
end
|
48
|
+
end
|
31
49
|
end
|
32
50
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
class FactoryTest < Test::Unit::TestCase
|
5
|
+
extend Forwardable
|
6
|
+
def_delegator FaradayStack, :build
|
7
|
+
|
8
|
+
class CustomConnection < Faraday::Connection
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_default_connection
|
12
|
+
assert_instance_of Faraday::Connection, FaradayStack.default_connection
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_build_subclass
|
16
|
+
assert_instance_of CustomConnection, build(CustomConnection)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_build_url
|
20
|
+
conn = FaradayStack.build('http://example.com')
|
21
|
+
assert_equal 'example.com', conn.host
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_build_url_in_options
|
25
|
+
conn = FaradayStack.build(:url => 'http://example.com')
|
26
|
+
assert_equal 'example.com', conn.host
|
27
|
+
end
|
28
|
+
end
|
@@ -7,6 +7,8 @@ class ResponseMiddlewareTest < Test::Unit::TestCase
|
|
7
7
|
b.use @json_handler
|
8
8
|
b.adapter :test do |stub|
|
9
9
|
stub.get('json') { [200, {'Content-Type' => 'application/json; charset=utf-8'}, "[1,2,3]"] }
|
10
|
+
stub.get('bad_mime') { [200, {'Content-Type' => 'text/javascript; charset=utf-8'}, "[1,2,3]"] }
|
11
|
+
stub.get('js') { [200, {'Content-Type' => 'text/javascript'}, "alert('hello')"] }
|
10
12
|
stub.get('blank') { [200, {'Content-Type' => 'application/json'}, ''] }
|
11
13
|
stub.get('nil') { [200, {'Content-Type' => 'application/json'}, nil] }
|
12
14
|
stub.get('bad_json') { [200, {'Content-Type' => 'application/json'}, '<body></body>']}
|
@@ -19,6 +21,10 @@ class ResponseMiddlewareTest < Test::Unit::TestCase
|
|
19
21
|
@conn.builder.swap @json_handler, @json_handler, :content_type => types
|
20
22
|
end
|
21
23
|
|
24
|
+
def with_mime_type_fix(*types)
|
25
|
+
@conn.builder.insert_after @json_handler, FaradayStack::ResponseJSON::MimeTypeFix, :content_type => types
|
26
|
+
end
|
27
|
+
|
22
28
|
def test_uses_json_to_parse_json_content
|
23
29
|
response = @conn.get('json')
|
24
30
|
assert response.success?
|
@@ -69,4 +75,19 @@ class ResponseMiddlewareTest < Test::Unit::TestCase
|
|
69
75
|
assert_equal 'text/html', response.headers['Content-Type']
|
70
76
|
assert_equal '<body></body>', response.body
|
71
77
|
end
|
78
|
+
|
79
|
+
def test_mime_type_fix
|
80
|
+
process_only('application/json')
|
81
|
+
with_mime_type_fix
|
82
|
+
response = @conn.get('bad_mime')
|
83
|
+
assert_equal 'application/json; charset=utf-8', response.headers['Content-Type']
|
84
|
+
assert_equal [1,2,3], response.body
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_mime_type_fix_conditional
|
88
|
+
process_only('application/json')
|
89
|
+
with_mime_type_fix
|
90
|
+
response = @conn.get('js')
|
91
|
+
assert_equal 'text/javascript', response.headers['Content-Type']
|
92
|
+
end
|
72
93
|
end
|
metadata
CHANGED
@@ -1,34 +1,45 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday-stack
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
6
10
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
- Mislav
|
11
|
+
authors:
|
12
|
+
- "Mislav Marohni\xC4\x87"
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
15
|
cert_chain: []
|
12
|
-
|
16
|
+
|
17
|
+
date: 2011-06-13 00:00:00 +02:00
|
13
18
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
16
21
|
name: faraday
|
17
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
24
|
none: false
|
19
|
-
requirements:
|
25
|
+
requirements:
|
20
26
|
- - ~>
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 6
|
31
|
+
version: "0.6"
|
23
32
|
type: :runtime
|
24
|
-
|
25
|
-
version_requirements: *2164745380
|
33
|
+
version_requirements: *id001
|
26
34
|
description:
|
27
35
|
email: mislav.marohnic@gmail.com
|
28
36
|
executables: []
|
37
|
+
|
29
38
|
extensions: []
|
39
|
+
|
30
40
|
extra_rdoc_files: []
|
31
|
-
|
41
|
+
|
42
|
+
files:
|
32
43
|
- lib/faraday-stack.rb
|
33
44
|
- lib/faraday_stack/addressable_patch.rb
|
34
45
|
- lib/faraday_stack/caching.rb
|
@@ -41,33 +52,42 @@ files:
|
|
41
52
|
- lib/faraday_stack/response_xml.rb
|
42
53
|
- lib/faraday_stack.rb
|
43
54
|
- test/caching_test.rb
|
55
|
+
- test/factory_test.rb
|
44
56
|
- test/follow_redirects_test.rb
|
45
57
|
- test/response_middleware_test.rb
|
46
58
|
- test/test_helper.rb
|
47
59
|
- README.md
|
48
|
-
has_rdoc:
|
60
|
+
has_rdoc: true
|
49
61
|
homepage: https://github.com/mislav/faraday-stack
|
50
62
|
licenses: []
|
63
|
+
|
51
64
|
post_install_message:
|
52
65
|
rdoc_options: []
|
53
|
-
|
66
|
+
|
67
|
+
require_paths:
|
54
68
|
- lib
|
55
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
70
|
none: false
|
57
|
-
requirements:
|
58
|
-
- -
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
|
61
|
-
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
78
|
none: false
|
63
|
-
requirements:
|
64
|
-
- -
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
67
85
|
requirements: []
|
86
|
+
|
68
87
|
rubyforge_project:
|
69
|
-
rubygems_version: 1.
|
88
|
+
rubygems_version: 1.3.7
|
70
89
|
signing_key:
|
71
90
|
specification_version: 3
|
72
91
|
summary: Great Faraday stack for consuming all kinds of APIs
|
73
92
|
test_files: []
|
93
|
+
|