This repository has been archived by the owner on Oct 20, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 82d3b15
Showing
7 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
require 'faraday_stack' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,35 @@ | |||
# encoding: utf-8 | |||
require 'faraday' | |||
require 'forwardable' | |||
|
|||
module FaradayStack | |||
extend Faraday::AutoloadHelper | |||
|
|||
autoload_all 'faraday_stack', | |||
:ResponseMiddleware => 'response_middleware', | |||
:ResponseJSON => 'response_json', | |||
:ResponseXML => 'response_xml' | |||
|
|||
# THE ÜBER STACK | |||
def self.default_connection | |||
@default_connection ||= self.build | |||
end | |||
|
|||
class << self | |||
extend Forwardable | |||
attr_writer :default_connection | |||
def_delegators :default_connection, :get, :post, :put, :head, :delete | |||
end | |||
|
|||
def self.build(url = nil, options = {}) | |||
Faraday::Connection.new(url, options) do |builder| | |||
builder.request :url_encoded | |||
builder.request :json | |||
builder.use ResponseJSON, :content_type => 'application/json' | |||
builder.use ResponseXML, :content_type => /[+\/]xml$/ | |||
builder.response :raise_error | |||
yield builder if block_given? | |||
builder.adapter Faraday.default_adapter | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,32 @@ | |||
module FaradayStack | |||
class ResponseJSON < ResponseMiddleware | |||
adapter_name = nil | |||
|
|||
# loads the JSON decoder either from yajl-ruby or activesupport | |||
dependency do | |||
require 'yajl' | |||
adapter_name = Yajl::Parser.name | |||
end | |||
|
|||
dependency do | |||
require 'active_support/json/decoding' | |||
adapter_name = ActiveSupport::JSON.name | |||
end unless loaded? | |||
|
|||
# defines a parser block depending on which adapter has loaded | |||
case adapter_name | |||
when 'Yajl::Parser' | |||
define_parser do |body| | |||
Yajl::Parser.parse(body) | |||
end | |||
when 'ActiveSupport::JSON' | |||
define_parser do |body| | |||
unless body.nil? or body.empty? | |||
result = ActiveSupport::JSON.decode(body) | |||
raise ActiveSupport::JSON.backend::ParseError if String === result | |||
result | |||
end | |||
end | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,66 @@ | |||
module FaradayStack | |||
# A base class for middleware that parses responses | |||
class ResponseMiddleware < Faraday::Response::Middleware | |||
CONTENT_TYPE = 'Content-Type'.freeze | |||
|
|||
# Executes a block which should try to require and reference dependent libraries | |||
def self.dependency | |||
yield | |||
rescue LoadError, NameError => error | |||
self.load_error = error | |||
end | |||
|
|||
class << self | |||
attr_accessor :parser | |||
end | |||
|
|||
# Stores a block that receives the body and should return a parsed result | |||
def self.define_parser(&block) | |||
@parser = block | |||
end | |||
|
|||
def self.inherited(subclass) | |||
super | |||
subclass.load_error = self.load_error | |||
subclass.parser = self.parser | |||
end | |||
|
|||
def initialize(app = nil, options = {}) | |||
super(app) | |||
@content_types = Array(options[:content_type]) | |||
end | |||
|
|||
# Override this to modify the environment after the response has finished. | |||
def on_complete(env) | |||
if process_response_type?(response_type(env)) | |||
env[:body] = parse(env[:body]) | |||
end | |||
end | |||
|
|||
# Parses the response body and returns the result. | |||
# Instead of overriding this method, consider using `define_parser` | |||
def parse(body) | |||
if self.class.parser | |||
begin | |||
self.class.parser.call(body) | |||
rescue | |||
raise Faraday::Error::ParsingError, $! | |||
end | |||
else | |||
body | |||
end | |||
end | |||
|
|||
def response_type(env) | |||
type = env[:response_headers][CONTENT_TYPE].to_s | |||
type = type.split(';', 2).first if type.index(';') | |||
type | |||
end | |||
|
|||
def process_response_type?(type) | |||
@content_types.empty? or @content_types.any? { |pattern| | |||
Regexp === pattern ? type =~ pattern : type == pattern | |||
} | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,12 @@ | |||
module FaradayStack | |||
class ResponseXML < ResponseMiddleware | |||
dependency do | |||
require 'nokogiri' | |||
Nokogiri::XML | |||
end | |||
|
|||
define_parser do |body| | |||
Nokogiri::XML body | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,72 @@ | |||
require 'test_helper' | |||
|
|||
class ResponseMiddlewareTest < Test::Unit::TestCase | |||
def setup | |||
@json_handler = FaradayStack::ResponseJSON | |||
@conn = Faraday.new do |b| | |||
b.use @json_handler | |||
b.adapter :test do |stub| | |||
stub.get('json') { [200, {'Content-Type' => 'application/json; charset=utf-8'}, "[1,2,3]"] } | |||
stub.get('blank') { [200, {'Content-Type' => 'application/json'}, ''] } | |||
stub.get('nil') { [200, {'Content-Type' => 'application/json'}, nil] } | |||
stub.get('bad_json') { [200, {'Content-Type' => 'application/json'}, '<body></body>']} | |||
stub.get('non_json') { [200, {'Content-Type' => 'text/html'}, '<body></body>']} | |||
end | |||
end | |||
end | |||
|
|||
def process_only(*types) | |||
@conn.builder.swap @json_handler, @json_handler, :content_type => types | |||
end | |||
|
|||
def test_uses_json_to_parse_json_content | |||
response = @conn.get('json') | |||
assert response.success? | |||
assert_equal [1,2,3], response.body | |||
end | |||
|
|||
def test_uses_json_to_parse_json_content_conditional | |||
process_only('application/json') | |||
response = @conn.get('json') | |||
assert response.success? | |||
assert_equal [1,2,3], response.body | |||
end | |||
|
|||
def test_uses_json_to_parse_json_content_conditional_with_regexp | |||
process_only(%r{/(x-)?json$}) | |||
response = @conn.get('json') | |||
assert response.success? | |||
assert_equal [1,2,3], response.body | |||
end | |||
|
|||
def test_uses_json_to_skip_blank_content | |||
response = @conn.get('blank') | |||
assert response.success? | |||
assert_nil response.body | |||
end | |||
|
|||
def test_uses_json_to_skip_nil_content | |||
response = @conn.get('nil') | |||
assert response.success? | |||
assert_nil response.body | |||
end | |||
|
|||
def test_uses_json_to_raise_Faraday_Error_Parsing_with_no_json_content | |||
assert_raises Faraday::Error::ParsingError do | |||
@conn.get('bad_json') | |||
end | |||
end | |||
|
|||
def test_non_json_response | |||
assert_raises Faraday::Error::ParsingError do | |||
@conn.get('non_json') | |||
end | |||
end | |||
|
|||
def test_non_json_response_conditional | |||
process_only('application/json') | |||
response = @conn.get('non_json') | |||
assert_equal 'text/html', response.headers['Content-Type'] | |||
assert_equal '<body></body>', response.body | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
require 'test/unit' | |||
require 'faraday_stack' |