faraday_middleware 0.7.0 → 0.8.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/.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
|