faraday_middleware 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +0 -1
- data/.travis.yml +1 -2
- data/CHANGELOG.md +9 -9
- data/Gemfile +3 -3
- data/README.md +2 -2
- data/Rakefile +9 -2
- data/faraday_middleware.gemspec +16 -24
- data/lib/faraday_middleware.rb +51 -11
- data/lib/faraday_middleware/addressable_patch.rb +20 -0
- data/lib/faraday_middleware/backwards_compatibility.rb +30 -0
- data/lib/faraday_middleware/instrumentation.rb +30 -0
- data/lib/faraday_middleware/rack_compatible.rb +76 -0
- data/lib/faraday_middleware/request/encode_json.rb +50 -0
- data/lib/faraday_middleware/request/oauth.rb +61 -0
- data/lib/faraday_middleware/request/oauth2.rb +60 -0
- data/lib/faraday_middleware/response/caching.rb +76 -0
- data/lib/faraday_middleware/response/follow_redirects.rb +53 -0
- data/lib/{faraday → faraday_middleware}/response/mashify.rb +2 -2
- data/lib/faraday_middleware/response/parse_json.rb +35 -0
- data/lib/faraday_middleware/response/parse_marshal.rb +10 -0
- data/lib/faraday_middleware/response/parse_xml.rb +11 -0
- data/lib/faraday_middleware/response/parse_yaml.rb +10 -0
- data/lib/faraday_middleware/response/rashify.rb +9 -0
- data/lib/faraday_middleware/response_middleware.rb +78 -0
- data/lib/faraday_middleware/version.rb +1 -1
- data/spec/caching_test.rb +122 -0
- data/spec/encode_json_spec.rb +95 -0
- data/spec/follow_redirects_spec.rb +33 -0
- data/spec/helper.rb +27 -12
- data/spec/mashify_spec.rb +8 -7
- data/spec/oauth2_spec.rb +100 -32
- data/spec/oauth_spec.rb +83 -28
- data/spec/parse_json_spec.rb +71 -46
- data/spec/parse_marshal_spec.rb +9 -26
- data/spec/parse_xml_spec.rb +56 -24
- data/spec/parse_yaml_spec.rb +40 -20
- data/spec/rashify_spec.rb +4 -3
- metadata +59 -57
- data/lib/faraday/request/oauth.rb +0 -23
- data/lib/faraday/request/oauth2.rb +0 -24
- data/lib/faraday/response/parse_json.rb +0 -20
- data/lib/faraday/response/parse_marshal.rb +0 -10
- data/lib/faraday/response/parse_xml.rb +0 -11
- data/lib/faraday/response/parse_yaml.rb +0 -11
- data/lib/faraday/response/rashify.rb +0 -19
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
### 0.0.2 September 25, 2010
|
4
|
-
|
5
|
-
* Mashify now handles arrays of non-hashes
|
6
|
-
|
7
|
-
### 0.0.1 June 27, 2010
|
8
|
-
|
9
|
-
* MultiJSON
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
### 0.0.2 September 25, 2010
|
4
|
+
|
5
|
+
* Mashify now handles arrays of non-hashes
|
6
|
+
|
7
|
+
### 0.0.1 June 27, 2010
|
8
|
+
|
9
|
+
* MultiJSON
|
10
10
|
* Mashify
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,11 +3,11 @@ Faraday Middleware
|
|
3
3
|
|
4
4
|
A collection of some useful [Faraday](https://github.com/technoweenie/faraday) middleware
|
5
5
|
|
6
|
-
Installation
|
6
|
+
<a name="installation">Installation</a>
|
7
7
|
------------
|
8
8
|
gem install faraday_middleware
|
9
9
|
|
10
|
-
Examples
|
10
|
+
<a name="examples">Examples</a>
|
11
11
|
--------
|
12
12
|
Let's decode the response body with [MultiJson](https://github.com/intridea/multi_json)!
|
13
13
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
|
3
|
+
task :default => [:enable_coverage, :spec, :test]
|
4
|
+
|
3
5
|
require 'bundler'
|
4
6
|
Bundler::GemHelper.install_tasks
|
5
7
|
|
6
8
|
require 'rspec/core/rake_task'
|
7
9
|
RSpec::Core::RakeTask.new(:spec)
|
8
10
|
|
9
|
-
task :
|
10
|
-
|
11
|
+
task :enable_coverage do
|
12
|
+
ENV['COVERAGE'] = 'yes' unless ENV['CI']
|
13
|
+
end
|
14
|
+
|
15
|
+
task :test do
|
16
|
+
sh 'ruby', '-Ilib', 'spec/caching_test.rb'
|
17
|
+
end
|
data/faraday_middleware.gemspec
CHANGED
@@ -1,31 +1,23 @@
|
|
1
1
|
require File.expand_path('../lib/faraday_middleware/version', __FILE__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
|
-
gem.
|
5
|
-
gem.
|
6
|
-
gem.description = gem.summary
|
7
|
-
|
8
|
-
gem.homepage = 'https://github.com/pengwynn/faraday_middleware'
|
9
|
-
|
10
|
-
gem.authors = ["Erik Michaels-Ober", "Wynn Netherland"]
|
11
|
-
gem.email = ['sferik@gmail.com', 'wynn.netherland@gmail.com']
|
12
|
-
|
13
|
-
gem.version = FaradayMiddleware::VERSION
|
14
|
-
|
15
|
-
gem.require_paths = ['lib']
|
16
|
-
gem.files = `git ls-files`.split("\n")
|
17
|
-
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
|
20
|
-
gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
|
21
|
-
|
22
|
-
gem.add_runtime_dependency 'faraday', '~> 0.7.3'
|
4
|
+
gem.add_dependency 'faraday', ['>= 0.7.4', '< 0.9']
|
5
|
+
gem.add_development_dependency 'multi_xml', '~> 0.2'
|
23
6
|
gem.add_development_dependency 'rake', '~> 0.9'
|
24
|
-
gem.add_development_dependency '
|
25
|
-
gem.add_development_dependency 'simplecov', '~> 0.4'
|
7
|
+
gem.add_development_dependency 'hashie', '~> 1.2'
|
26
8
|
gem.add_development_dependency 'rash', '~> 0.3'
|
27
|
-
gem.add_development_dependency '
|
28
|
-
gem.add_development_dependency 'multi_xml', '~> 0.2'
|
29
|
-
gem.add_development_dependency 'oauth2', '~> 0.5.0'
|
9
|
+
gem.add_development_dependency 'rspec', '~> 2.6'
|
30
10
|
gem.add_development_dependency 'simple_oauth', '~> 0.1'
|
11
|
+
gem.add_development_dependency 'rack-cache', '~> 1.1'
|
12
|
+
gem.authors = ["Erik Michaels-Ober", "Wynn Netherland"]
|
13
|
+
gem.description = %q{Various middleware for Faraday}
|
14
|
+
gem.email = ['sferik@gmail.com', 'wynn.netherland@gmail.com']
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.homepage = 'https://github.com/pengwynn/faraday_middleware'
|
17
|
+
gem.name = 'faraday_middleware'
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
|
20
|
+
gem.summary = gem.description
|
21
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
gem.version = FaradayMiddleware::VERSION
|
31
23
|
end
|
data/lib/faraday_middleware.rb
CHANGED
@@ -1,15 +1,55 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module FaradayMiddleware
|
4
|
+
class << self
|
5
|
+
middleware = {
|
6
|
+
:OAuth => 'request/oauth',
|
7
|
+
:OAuth2 => 'request/oauth2',
|
8
|
+
:EncodeJson => 'request/encode_json',
|
9
|
+
:Mashify => 'response/mashify',
|
10
|
+
:Rashify => 'response/rashify',
|
11
|
+
:ParseJson => 'response/parse_json',
|
12
|
+
:ParseXml => 'response/parse_xml',
|
13
|
+
:ParseMarshal => 'response/parse_marshal',
|
14
|
+
:ParseYaml => 'response/parse_yaml',
|
15
|
+
:Caching => 'response/caching',
|
16
|
+
:RackCompatible => 'rack_compatible',
|
17
|
+
:FollowRedirects => 'response/follow_redirects',
|
18
|
+
:Instrumentation => 'instrumentation'
|
19
|
+
}
|
20
|
+
|
21
|
+
# autoload without the autoload
|
22
|
+
define_method(:const_missing) { |const|
|
23
|
+
if middleware.member? const
|
24
|
+
require "faraday_middleware/#{middleware[const]}"
|
25
|
+
raise NameError, "missing #{const} middleware" unless const_defined? const
|
26
|
+
const_get const
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
if Faraday.respond_to? :register_middleware
|
34
|
+
Faraday.register_middleware :request,
|
35
|
+
:oauth => lambda { OAuth },
|
36
|
+
:oauth2 => lambda { OAuth2 },
|
37
|
+
:json => lambda { EncodeJson }
|
7
38
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
39
|
+
Faraday.register_middleware :response,
|
40
|
+
:mashify => lambda { Mashify },
|
41
|
+
:rashify => lambda { Rashify },
|
42
|
+
:json => lambda { ParseJson },
|
43
|
+
:json_fix => lambda { ParseJson::MimeTypeFix },
|
44
|
+
:xml => lambda { ParseXml },
|
45
|
+
:marshal => lambda { ParseMarshal },
|
46
|
+
:yaml => lambda { ParseYaml },
|
47
|
+
:caching => lambda { Caching },
|
48
|
+
:follow_redirects => lambda { FollowRedirects }
|
49
|
+
|
50
|
+
Faraday.register_middleware \
|
51
|
+
:instrumentation => lambda { Instrumentation }
|
52
|
+
end
|
15
53
|
end
|
54
|
+
|
55
|
+
require 'faraday_middleware/backwards_compatibility'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
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
|
9
|
+
|
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
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
deprecation_warning = lambda { |old, new, trace|
|
2
|
+
warn "Deprecation warning: #{old} is deprecated; use #{new}"
|
3
|
+
warn trace[0,10].join("\n") if $DEBUG
|
4
|
+
}
|
5
|
+
|
6
|
+
Faraday::Request.extend Module.new {
|
7
|
+
legacy = [:OAuth, :OAuth2]
|
8
|
+
define_method(:const_missing) { |const|
|
9
|
+
if legacy.include? const
|
10
|
+
klass = FaradayMiddleware.const_get(const)
|
11
|
+
deprecation_warning.call "Faraday::Request::#{const}", klass.name, caller
|
12
|
+
const_set const, klass
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
Faraday::Response.extend Module.new {
|
20
|
+
legacy = [:Mashify, :Rashify, :ParseJson, :ParseMarshal, :ParseXml, :ParseYaml]
|
21
|
+
define_method(:const_missing) { |const|
|
22
|
+
if legacy.include? const
|
23
|
+
klass = FaradayMiddleware.const_get(const)
|
24
|
+
deprecation_warning.call "Faraday::Response::#{const}", klass.name, caller
|
25
|
+
const_set const, klass
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module FaradayMiddleware
|
4
|
+
# Public: Instruments requests using Active Support.
|
5
|
+
#
|
6
|
+
# Measures time spent only for synchronous requests.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# ActiveSupport::Notifications.subscribe('request.faraday') do |name, start_time, end_time, _, env|
|
11
|
+
# url = env[:url]
|
12
|
+
# http_method = env[:method].to_s.upcase
|
13
|
+
# duration = end_time - start_time
|
14
|
+
# $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
|
15
|
+
# end
|
16
|
+
class Instrumentation < Faraday::Middleware
|
17
|
+
dependency 'active_support/notifications'
|
18
|
+
|
19
|
+
def initialize(app, options = {})
|
20
|
+
super(app)
|
21
|
+
@name = options.fetch(:name, 'request.faraday')
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(env)
|
25
|
+
ActiveSupport::Notifications.instrument(@name, env) do
|
26
|
+
@app.call(env)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module FaradayMiddleware
|
4
|
+
# Wraps a handler originally written for Rack to make it compatible with Faraday.
|
5
|
+
#
|
6
|
+
# Experimental. Only handles changes in request headers.
|
7
|
+
class RackCompatible
|
8
|
+
def initialize(app, rack_handler, *args)
|
9
|
+
# tiny middleware that decomposes a Faraday::Response to standard Rack
|
10
|
+
# array: [status, headers, body]
|
11
|
+
compatible_app = lambda do |env|
|
12
|
+
restore_env(env)
|
13
|
+
response = app.call(env)
|
14
|
+
[response.status, response.headers, Array(response.body)]
|
15
|
+
end
|
16
|
+
@rack = rack_handler.new(compatible_app, *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
prepare_env(env)
|
21
|
+
rack_response = @rack.call(env)
|
22
|
+
finalize_response(env, rack_response)
|
23
|
+
end
|
24
|
+
|
25
|
+
NonPrefixedHeaders = %w[CONTENT_LENGTH CONTENT_TYPE]
|
26
|
+
|
27
|
+
# faraday to rack-compatible
|
28
|
+
def prepare_env(env)
|
29
|
+
env[:request_headers].each do |name, value|
|
30
|
+
name = name.upcase.tr('-', '_')
|
31
|
+
name = "HTTP_#{name}" unless NonPrefixedHeaders.include? name
|
32
|
+
env[name] = value
|
33
|
+
end
|
34
|
+
|
35
|
+
url = env[:url]
|
36
|
+
env['rack.url_scheme'] = url.scheme
|
37
|
+
env['PATH_INFO'] = url.path
|
38
|
+
env['SERVER_PORT'] = url.respond_to?(:inferred_port) ? url.inferred_port : url.port
|
39
|
+
env['QUERY_STRING'] = url.query
|
40
|
+
env['REQUEST_METHOD'] = env[:method].to_s.upcase
|
41
|
+
|
42
|
+
env['rack.errors'] ||= StringIO.new
|
43
|
+
|
44
|
+
env
|
45
|
+
end
|
46
|
+
|
47
|
+
# rack to faraday-compatible
|
48
|
+
def restore_env(env)
|
49
|
+
headers = env[:request_headers]
|
50
|
+
headers.clear
|
51
|
+
|
52
|
+
env.each do |name, value|
|
53
|
+
next unless String === name
|
54
|
+
if NonPrefixedHeaders.include? name or name.index('HTTP_') == 0
|
55
|
+
name = name.sub(/^HTTP_/, '').downcase.tr('_', '-')
|
56
|
+
headers[name] = value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
env[:method] = env['REQUEST_METHOD'].downcase.to_sym
|
61
|
+
env
|
62
|
+
end
|
63
|
+
|
64
|
+
def finalize_response(env, rack_response)
|
65
|
+
status, headers, body = rack_response
|
66
|
+
body = body.inject('') { |str, part| str << part }
|
67
|
+
headers = Faraday::Utils::Headers.new(headers) unless Faraday::Utils::Headers === headers
|
68
|
+
|
69
|
+
response_env = { :status => status, :body => body, :response_headers => headers }
|
70
|
+
|
71
|
+
env[:response] ||= Faraday::Response.new({})
|
72
|
+
env[:response].env.update(response_env)
|
73
|
+
env[:response]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module FaradayMiddleware
|
4
|
+
# Request middleware that encodes the body as JSON.
|
5
|
+
#
|
6
|
+
# Processes only requests with matching Content-type or those without a type.
|
7
|
+
# If a request doesn't have a type but has a body, it sets the Content-type
|
8
|
+
# to JSON MIME-type.
|
9
|
+
#
|
10
|
+
# Doesn't try to encode bodies that already are in string form.
|
11
|
+
class EncodeJson < Faraday::Middleware
|
12
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
13
|
+
MIME_TYPE = 'application/json'.freeze
|
14
|
+
|
15
|
+
dependency 'json'
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
match_content_type(env) do |data|
|
19
|
+
env[:body] = encode data
|
20
|
+
end
|
21
|
+
@app.call env
|
22
|
+
end
|
23
|
+
|
24
|
+
def encode(data)
|
25
|
+
JSON.dump data
|
26
|
+
end
|
27
|
+
|
28
|
+
def match_content_type(env)
|
29
|
+
if process_request?(env)
|
30
|
+
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
31
|
+
yield env[:body] unless env[:body].respond_to?(:to_str)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_request?(env)
|
36
|
+
type = request_type(env)
|
37
|
+
has_body?(env) and (type.empty? or type == MIME_TYPE)
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_body?(env)
|
41
|
+
body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
|
42
|
+
end
|
43
|
+
|
44
|
+
def request_type(env)
|
45
|
+
type = env[:request_headers][CONTENT_TYPE].to_s
|
46
|
+
type = type.split(';', 2).first if type.index(';')
|
47
|
+
type
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module FaradayMiddleware
|
4
|
+
# Public: Uses the simple_oauth library to sign requests according the
|
5
|
+
# OAuth protocol.
|
6
|
+
#
|
7
|
+
# The options for this middleware are forwarded to SimpleOAuth::Header:
|
8
|
+
# :consumer_key, :consumer_secret, :token, :token_secret. All these
|
9
|
+
# parameters are optional.
|
10
|
+
#
|
11
|
+
# The signature is added to the "Authorization" HTTP request header. If the
|
12
|
+
# value for this header already exists, it is not overriden.
|
13
|
+
#
|
14
|
+
# For requests that have parameters in the body, such as POST, this
|
15
|
+
# middleware expects them to be in Hash form, i.e. not encoded to string.
|
16
|
+
# This means this middleware has to be positioned on the stack before any
|
17
|
+
# encoding middleware such as UrlEncoded.
|
18
|
+
class OAuth < Faraday::Middleware
|
19
|
+
dependency 'simple_oauth'
|
20
|
+
|
21
|
+
AUTH_HEADER = 'Authorization'.freeze
|
22
|
+
|
23
|
+
def initialize(app, options)
|
24
|
+
super(app)
|
25
|
+
@options = options
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
env[:request_headers][AUTH_HEADER] ||= oauth_header(env).to_s if sign_request?(env)
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
|
33
|
+
def oauth_header(env)
|
34
|
+
SimpleOAuth::Header.new env[:method],
|
35
|
+
env[:url].to_s,
|
36
|
+
signature_params(body_params(env)),
|
37
|
+
oauth_options(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
def sign_request?(env)
|
41
|
+
!!env[:request].fetch(:oauth, true)
|
42
|
+
end
|
43
|
+
|
44
|
+
def oauth_options(env)
|
45
|
+
if extra = env[:request][:oauth] and extra.is_a? Hash and !extra.empty?
|
46
|
+
@options.merge extra
|
47
|
+
else
|
48
|
+
@options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def body_params(env)
|
53
|
+
env[:body] || {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def signature_params(params)
|
57
|
+
params.empty? ? params :
|
58
|
+
params.reject {|k,v| v.respond_to?(:content_type) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|