This repository has been archived by the owner on Jun 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cleaned up and documented the request middleware
- Loading branch information
Thomas Stachl
committed
May 28, 2014
1 parent
8f70833
commit 1c52a9a
Showing
4 changed files
with
136 additions
and
57 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 | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,25 @@ | ||
module DeskApi::Request | ||
class EncodeJson < Faraday::Middleware | ||
dependency 'json' | ||
module DeskApi | ||
module Request | ||
# {DeskApi::Request::EncodeJson} is the Faraday middleware | ||
# that dumps a json string from whatever is specified in | ||
# the request body. It also sets the "Content-Type" header. | ||
# | ||
# @author Thomas Stachl <tstachl@salesforce.com> | ||
# @copyright Copyright (c) 2013-2014 Thomas Stachl | ||
# @license MIT | ||
class EncodeJson < Faraday::Middleware | ||
dependency 'json' | ||
|
||
def call(env) | ||
env[:request_headers]['Content-Type'] = 'application/json' | ||
env[:body] = ::JSON.dump(env[:body]) if env[:body] and not env[:body].to_s.empty? | ||
@app.call env | ||
# Changes the request before it gets sent | ||
# | ||
# @param env [Hash] the request hash | ||
def call(env) | ||
env[:request_headers]['Content-Type'] = 'application/json' | ||
if env[:body] && !env[:body].to_s.empty? | ||
env[:body] = ::JSON.dump(env[:body]) | ||
end | ||
@app.call env | ||
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 | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,40 @@ | ||
module DeskApi::Request | ||
class OAuth < Faraday::Middleware | ||
dependency 'simple_oauth' | ||
module DeskApi | ||
module Request | ||
# {DeskApi::Request::OAuth} is the Faraday middleware to | ||
# sign requests with an OAuth header. | ||
# | ||
# @author Thomas Stachl <tstachl@salesforce.com> | ||
# @copyright Copyright (c) 2013-2014 Thomas Stachl | ||
# @license MIT | ||
class OAuth < Faraday::Middleware | ||
dependency 'simple_oauth' | ||
|
||
def initialize(app, options) | ||
super(app) | ||
@options = options | ||
end | ||
# Initializies the middleware and sets options | ||
# | ||
# @param app [Hash] the faraday environment hash | ||
# @param options [Hash] additional options | ||
def initialize(app, options) | ||
super(app) | ||
@options = options | ||
end | ||
|
||
def call(env) | ||
env[:request_headers]['Authorization'] = oauth(env).to_s | ||
@app.call env | ||
end | ||
# Changes the request before it gets sent | ||
# | ||
# @param env [Hash] the request hash | ||
def call(env) | ||
env[:request_headers]['Authorization'] = oauth(env).to_s | ||
@app.call env | ||
end | ||
|
||
private | ||
|
||
private | ||
def oauth(env) | ||
SimpleOAuth::Header.new env[:method], env[:url].to_s, {}, @options | ||
# Returns the OAuth header | ||
# | ||
# @param env [Hash] the request hash | ||
# @return [String] | ||
def oauth(env) | ||
SimpleOAuth::Header.new env[:method], env[:url].to_s, {}, @options | ||
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 | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,92 @@ | ||
module DeskApi::Request | ||
class Retry < Faraday::Middleware | ||
def initialize(app, options = {}) | ||
@max = options[:max] || 3 | ||
@interval = options[:interval] || 10 | ||
super(app) | ||
end | ||
module DeskApi | ||
module Request | ||
# {DeskApi::Request::Retry} is a Faraday middleware that | ||
# retries failed requests up to 3 times. It also includes | ||
# desk.com's rate limiting which are retried only once. | ||
# | ||
# @author Thomas Stachl <tstachl@salesforce.com> | ||
# @copyright Copyright (c) 2013-2014 Thomas Stachl | ||
# @license MIT | ||
class Retry < Faraday::Middleware | ||
class << self | ||
# Returns an array of errors that should be retried. | ||
# | ||
# @return [Array] | ||
def errors | ||
@exceptions ||= [ | ||
Errno::ETIMEDOUT, | ||
'Timeout::Error', | ||
Faraday::Error::TimeoutError, | ||
DeskApi::Error::TooManyRequests | ||
] | ||
end | ||
end | ||
|
||
def call(env) | ||
retries = @max | ||
request_body = env[:body] | ||
begin | ||
env[:body] = request_body | ||
@app.call(env) | ||
rescue DeskApi::Error::TooManyRequests => e | ||
if retries > 0 | ||
retries = 0 | ||
sleep e.rate_limit.reset_in | ||
# Initializies the middleware and sets options | ||
# | ||
# @param app [Hash] the faraday environment hash | ||
# @param options [Hash] additional options | ||
def initialize(app, options = {}) | ||
@max = options[:max] || 3 | ||
@interval = options[:interval] || 10 | ||
super(app) | ||
end | ||
|
||
# Rescues exceptions and retries the request | ||
# | ||
# @param env [Hash] the request hash | ||
def call(env) | ||
retries = @max | ||
request_body = env[:body] | ||
begin | ||
env[:body] = request_body | ||
@app.call(env) | ||
rescue exception_matcher => err | ||
raise unless calc(err, retries) { |x| retries = x } > 0 | ||
sleep interval(err) | ||
retry | ||
end | ||
raise | ||
rescue exception_matcher | ||
if retries > 0 | ||
retries -= 1 | ||
sleep @interval | ||
retry | ||
end | ||
|
||
# Calculates the retries based on the error | ||
# | ||
# @param err [StandardError] the error that has been thrown | ||
# @param retries [Integer] current retry count | ||
# @return [Integer] | ||
def calc(err, retries, &block) | ||
if err.kind_of?(DeskApi::Error::TooManyRequests) | ||
block.call(0) | ||
else | ||
block.call(retries - 1) | ||
end | ||
end | ||
|
||
# Returns the interval for the specific error | ||
# | ||
# @param err [StandardError] the error that has been thrown | ||
# @return [Integer] | ||
def interval(err) | ||
if err.kind_of?(DeskApi::Error::TooManyRequests) | ||
err.rate_limit.reset_in | ||
else | ||
@interval | ||
end | ||
raise | ||
end | ||
end | ||
|
||
def exception_matcher | ||
exceptions = [Errno::ETIMEDOUT, 'Timeout::Error', Faraday::Error::TimeoutError] | ||
matcher = Module.new | ||
(class << matcher; self; end).class_eval do | ||
define_method(:===) do |error| | ||
exceptions.any? do |ex| | ||
if ex.is_a? Module then error.is_a? ex | ||
else error.class.to_s == ex.to_s | ||
# Returns an exception matcher | ||
# | ||
# @return [Module] | ||
def exception_matcher | ||
matcher = Module.new | ||
(class << matcher; self; end).class_eval do | ||
define_method(:===) do |error| | ||
Retry.errors.any? do |ex| | ||
ex.is_a?(Module) ? error.is_a?(ex) : error.class.to_s == ex.to_s | ||
end | ||
end | ||
end | ||
matcher | ||
end | ||
matcher | ||
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