mirror of
https://github.com/stripe/stripe-ruby.git
synced 2025-08-24 00:00:51 -04:00
Move to an alternative system based on StripeClient
This commit is contained in:
parent
593bbab53f
commit
1886d9a625
2
Rakefile
2
Rakefile
@ -10,7 +10,7 @@ desc "update bundled certs"
|
||||
task :update_certs do
|
||||
require "restclient"
|
||||
File.open(File.join(File.dirname(__FILE__), 'lib', 'data', 'ca-certificates.crt'), 'w') do |file|
|
||||
resp = RestClient.get "https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt"
|
||||
resp = Faraday.get "https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt"
|
||||
abort("bad response when fetching bundle") unless resp.code == 200
|
||||
file.write(resp.to_str)
|
||||
end
|
||||
|
173
lib/stripe.rb
173
lib/stripe.rb
@ -6,7 +6,7 @@ require 'rbconfig'
|
||||
require 'set'
|
||||
require 'socket'
|
||||
|
||||
require 'rest-client'
|
||||
require 'faraday'
|
||||
require 'json'
|
||||
|
||||
# Version
|
||||
@ -22,6 +22,7 @@ require 'stripe/api_operations/request'
|
||||
# API resource support classes
|
||||
require 'stripe/errors'
|
||||
require 'stripe/util'
|
||||
require 'stripe/stripe_client'
|
||||
require 'stripe/stripe_object'
|
||||
require 'stripe/stripe_response'
|
||||
require 'stripe/list_object'
|
||||
@ -67,35 +68,6 @@ require 'stripe/transfer'
|
||||
module Stripe
|
||||
DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
||||
|
||||
# Exceptions which we'd like to retry. This includes both socket errors that
|
||||
# may represent an intermittent problem and some special HTTP statuses.
|
||||
RETRY_EXCEPTIONS = [
|
||||
# Destination refused the connection. This could occur from a single
|
||||
# saturated server, so retry in case it's intermittent.
|
||||
Errno::ECONNREFUSED,
|
||||
|
||||
# Connection reset. This occasionally occurs on a server problem, and
|
||||
# deserves a retry because the server should terminate all requests
|
||||
# properly even if they were invalid.
|
||||
Errno::ECONNRESET,
|
||||
|
||||
# Timed out making the connection. It's worth retrying under this
|
||||
# circumstance.
|
||||
Errno::ETIMEDOUT,
|
||||
|
||||
# A server may respond with a 409 to indicate that there is a concurrent
|
||||
# request executing with the same idempotency key. In the case that a
|
||||
# request failed due to a connection problem and the client has retried too
|
||||
# early, but the server is still executing the old request, we would like
|
||||
# the client to continue retrying until getting a "real" response status
|
||||
# back.
|
||||
RestClient::Conflict,
|
||||
|
||||
# Retry on timeout-related problems. This shouldn't be lumped in with HTTP
|
||||
# exceptions, but with RestClient it is.
|
||||
RestClient::RequestTimeout,
|
||||
].freeze
|
||||
|
||||
@api_base = 'https://api.stripe.com'
|
||||
@connect_base = 'https://connect.stripe.com'
|
||||
@uploads_base = 'https://uploads.stripe.com'
|
||||
@ -153,7 +125,18 @@ module Stripe
|
||||
end
|
||||
end
|
||||
|
||||
def self.request(method, url, api_key, params={}, headers={}, api_base_url=nil)
|
||||
# A default Faraday connection to be used when one isn't configured. This
|
||||
# object should never be mutated, and instead instantiating your own
|
||||
# connection and wrapping it in a StripeClient object should be preferred.
|
||||
def self.default_conn
|
||||
@default_conn ||= Faraday.new do |conn|
|
||||
faraday.request :raise_error
|
||||
faraday.request :url_encoded
|
||||
farday.adapter Faraday.default_adapter
|
||||
end
|
||||
end
|
||||
|
||||
def self.request(conn, method, url, api_key, params, headers, api_base_url)
|
||||
api_base_url = api_base_url || @api_base
|
||||
|
||||
unless api_key ||= @api_key
|
||||
@ -171,19 +154,6 @@ module Stripe
|
||||
'email support@stripe.com if you have any questions.)')
|
||||
end
|
||||
|
||||
if verify_ssl_certs
|
||||
request_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
||||
:ssl_cert_store => ca_store}
|
||||
else
|
||||
request_opts = {:verify_ssl => false}
|
||||
unless @verify_ssl_warned
|
||||
@verify_ssl_warned = true
|
||||
$stderr.puts("WARNING: Running without SSL cert verification. " \
|
||||
"You should never do this in production. " \
|
||||
"Execute 'Stripe.verify_ssl_certs = true' to enable verification.")
|
||||
end
|
||||
end
|
||||
|
||||
params = Util.objects_to_ids(params)
|
||||
url = api_url(url, api_base_url)
|
||||
|
||||
@ -200,18 +170,42 @@ module Stripe
|
||||
end
|
||||
end
|
||||
|
||||
request_opts.update(:headers => request_headers(api_key, method).update(headers),
|
||||
:method => method, :open_timeout => open_timeout,
|
||||
:payload => payload, :url => url, :timeout => read_timeout)
|
||||
http_resp = execute_request_with_rescues(api_base_url, 0) do
|
||||
conn.run_request(
|
||||
method,
|
||||
url,
|
||||
payload,
|
||||
# TODO: Convert RestClient-style parameters.
|
||||
request_headers(api_key, method).update(headers)
|
||||
) do |req|
|
||||
req.options.open_timeout = open_timeout
|
||||
req.options.timeout = read_timeout
|
||||
|
||||
http_resp = execute_request_with_rescues(request_opts, api_base_url)
|
||||
if verify_ssl_Certs
|
||||
req.ssl.verify = true
|
||||
req.ssl.cert_store = ca_store
|
||||
else
|
||||
req.ssl.verify = false
|
||||
|
||||
unless @verify_ssl_warned
|
||||
@verify_ssl_warned = true
|
||||
$stderr.puts("WARNING: Running without SSL cert verification. " \
|
||||
"You should never do this in production. " \
|
||||
"Execute 'Stripe.verify_ssl_certs = true' to enable verification.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
resp = StripeResponse.from_rest_client_response(http_resp)
|
||||
resp = StripeResponse.from_faraday_response(http_resp)
|
||||
rescue JSON::ParserError
|
||||
raise general_api_error(http_resp.code, http_resp.body)
|
||||
end
|
||||
|
||||
# Allows StripeClient#request to return a response object to a caller.
|
||||
StripeClient.set_last_response(resp)
|
||||
|
||||
[resp, api_key]
|
||||
end
|
||||
|
||||
@ -225,13 +219,9 @@ module Stripe
|
||||
|
||||
private
|
||||
|
||||
def self.execute_request(opts)
|
||||
RestClient::Request.execute(opts)
|
||||
end
|
||||
|
||||
def self.execute_request_with_rescues(request_opts, api_base_url, retry_count = 0)
|
||||
def self.execute_request_with_rescues(api_base_url, retry_count, &block)
|
||||
begin
|
||||
response = execute_request(request_opts)
|
||||
block.call
|
||||
|
||||
# We rescue all exceptions from a request so that we have an easy spot to
|
||||
# implement our retry logic across the board. We'll re-raise if it's a type
|
||||
@ -244,18 +234,8 @@ module Stripe
|
||||
end
|
||||
|
||||
case e
|
||||
when SocketError
|
||||
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
||||
|
||||
when RestClient::ExceptionWithResponse
|
||||
if e.response
|
||||
handle_api_error(e.response)
|
||||
else
|
||||
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
||||
end
|
||||
|
||||
when RestClient::Exception, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError
|
||||
response = handle_restclient_error(e, request_opts, retry_count, api_base_url)
|
||||
when Faraday::ClientError
|
||||
response = handle_faraday_error(e, retry_count, api_base_url)
|
||||
|
||||
# Only handle errors when we know we can do so, and re-raise otherwise.
|
||||
# This should be pretty infrequent.
|
||||
@ -305,7 +285,7 @@ module Stripe
|
||||
|
||||
def self.handle_api_error(http_resp)
|
||||
begin
|
||||
resp = StripeResponse.from_rest_client_response(http_resp)
|
||||
resp = StripeResponse.from_faraday_response(http_resp)
|
||||
error = resp.data[:error]
|
||||
raise StripeError.new unless error && error.is_a?(Hash)
|
||||
|
||||
@ -344,37 +324,25 @@ module Stripe
|
||||
raise(error)
|
||||
end
|
||||
|
||||
def self.handle_restclient_error(e, request_opts, retry_count, api_base_url=nil)
|
||||
|
||||
api_base_url = @api_base unless api_base_url
|
||||
connection_message = "Please check your internet connection and try again. " \
|
||||
"If this problem persists, you should check Stripe's service status at " \
|
||||
"https://twitter.com/stripestatus, or let us know at support@stripe.com."
|
||||
|
||||
def self.handle_faraday_error(e, retry_count, api_base_url=nil)
|
||||
case e
|
||||
when RestClient::RequestTimeout
|
||||
message = "Could not connect to Stripe (#{api_base_url}). #{connection_message}"
|
||||
when Faraday::ConnectFailed
|
||||
message = "Unexpected error communicating when trying to connect to Stripe. " \
|
||||
"You may be seeing this message because your DNS is not working. " \
|
||||
"To check, try running 'host stripe.com' from the command line."
|
||||
|
||||
when RestClient::ServerBrokeConnection
|
||||
message = "The connection to the server (#{api_base_url}) broke before the " \
|
||||
"request completed. #{connection_message}"
|
||||
|
||||
when OpenSSL::SSL::SSLError
|
||||
when Faraday::SSLError
|
||||
message = "Could not establish a secure connection to Stripe, you may " \
|
||||
"need to upgrade your OpenSSL version. To check, try running " \
|
||||
"'openssl s_client -connect api.stripe.com:443' from the " \
|
||||
"command line."
|
||||
|
||||
when RestClient::SSLCertificateNotVerified
|
||||
message = "Could not verify Stripe's SSL certificate. " \
|
||||
"Please make sure that your network is not intercepting certificates. " \
|
||||
"(Try going to https://api.stripe.com/v1 in your browser.) " \
|
||||
"If this problem persists, let us know at support@stripe.com."
|
||||
|
||||
when SocketError
|
||||
message = "Unexpected error communicating when trying to connect to Stripe. " \
|
||||
"You may be seeing this message because your DNS is not working. " \
|
||||
"To check, try running 'host stripe.com' from the command line."
|
||||
when Faraday::TimeoutError
|
||||
api_base_url = @api_base unless api_base_url
|
||||
message = "Could not connect to Stripe (#{api_base_url}). " \
|
||||
"Please check your internet connection and try again. " \
|
||||
"If this problem persists, you should check Stripe's service status at " \
|
||||
"https://twitter.com/stripestatus, or let us know at support@stripe.com."
|
||||
|
||||
else
|
||||
message = "Unexpected error communicating with Stripe. " \
|
||||
@ -413,9 +381,26 @@ module Stripe
|
||||
end
|
||||
end
|
||||
|
||||
# Checks if an error is a problem that we should retry on. This includes both
|
||||
# socket errors that may represent an intermittent problem and some special
|
||||
# HTTP statuses.
|
||||
def self.should_retry?(e, retry_count)
|
||||
retry_count < self.max_network_retries &&
|
||||
RETRY_EXCEPTIONS.any? { |klass| e.is_a?(klass) }
|
||||
return false if retry_count >= self.max_network_retries
|
||||
|
||||
# Retry on timeout-related problems (either on open or read).
|
||||
return true if e.is_a?(Faraday::TimeoutError)
|
||||
|
||||
# Destination refused the connection, the connection was reset, or a
|
||||
# variety of other connection failures. This could occur from a single
|
||||
# saturated server, so retry in case it's intermittent.
|
||||
return true if e.is_a?(Faraday::ConnectionFailed)
|
||||
|
||||
if e.is_a?(Faraday::ClientError) && e.response
|
||||
# 409 conflict
|
||||
return true if e.response.status == 409
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def self.sleep_time(retry_count)
|
||||
|
@ -37,8 +37,8 @@ module Stripe
|
||||
|
||||
def reject(params={}, opts={})
|
||||
opts = Util.normalize_opts(opts)
|
||||
self.response, opts = request(:post, resource_url + '/reject', params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, resource_url + '/reject', params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
# Somewhat unfortunately, we attempt to do a special encoding trick when
|
||||
@ -95,7 +95,7 @@ module Stripe
|
||||
opts = {:api_base => Stripe.connect_base}.merge(Util.normalize_opts(opts))
|
||||
resp, opts = request(:post, '/oauth/deauthorize', { 'client_id' => client_id, 'stripe_user_id' => self.id }, opts)
|
||||
opts.delete(:api_base) # the api_base here is a one-off, don't persist it
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
|
||||
ARGUMENT_NOT_PROVIDED = Object.new
|
||||
|
@ -3,7 +3,7 @@ module Stripe
|
||||
module Create
|
||||
def create(params={}, opts={})
|
||||
resp, opts = request(:post, resource_url, params, opts)
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,8 +3,8 @@ module Stripe
|
||||
module Delete
|
||||
def delete(params={}, opts={})
|
||||
opts = Util.normalize_opts(opts)
|
||||
self.response, opts = request(:delete, resource_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:delete, resource_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -6,7 +6,6 @@ module Stripe
|
||||
|
||||
resp, opts = request(:get, resource_url, filters, opts)
|
||||
obj = ListObject.construct_from(resp.data, opts)
|
||||
obj.response = resp
|
||||
|
||||
# set filters so that we can fetch the same limit, expansions, and
|
||||
# predicates when accessing the next and previous pages
|
||||
|
@ -2,17 +2,19 @@ module Stripe
|
||||
module APIOperations
|
||||
module Request
|
||||
module ClassMethods
|
||||
OPTS_KEYS_TO_PERSIST = Set[:api_key, :api_base, :stripe_account, :stripe_version]
|
||||
OPTS_KEYS_TO_PERSIST = Set[:api_key, :api_base, :conn, :stripe_account, :stripe_version]
|
||||
|
||||
def request(method, url, params={}, opts={})
|
||||
opts = Util.normalize_opts(opts)
|
||||
opts[:conn] ||= Stripe.default_conn
|
||||
|
||||
headers = opts.clone
|
||||
api_key = headers.delete(:api_key)
|
||||
api_base = headers.delete(:api_base)
|
||||
conn = headers.delete[:conn]
|
||||
# Assume all remaining opts must be headers
|
||||
|
||||
resp, opts[:api_key] = Stripe.request(method, url, api_key, params, headers, api_base)
|
||||
resp, opts[:api_key] = Stripe.request(conn, method, url, api_key, params, headers, api_base)
|
||||
|
||||
# Hash#select returns an array before 1.9
|
||||
opts_to_persist = {}
|
||||
|
@ -22,7 +22,7 @@ module Stripe
|
||||
end
|
||||
|
||||
resp, opts = request(:post, "#{resource_url}/#{id}", params, opts)
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
end
|
||||
|
||||
@ -57,8 +57,8 @@ module Stripe
|
||||
# generated a uri for this object with an identifier baked in
|
||||
values.delete(:id)
|
||||
|
||||
self.response, opts = request(:post, save_url, values, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, save_url, values, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
|
@ -2,13 +2,6 @@ module Stripe
|
||||
class APIResource < StripeObject
|
||||
include Stripe::APIOperations::Request
|
||||
|
||||
# Response contains a StripeResponse object that has some basic information
|
||||
# about the response that conveyed the API resource.
|
||||
#
|
||||
# Note that this is only set on the top-level API resource returned by an
|
||||
# API operation. It will hold a nil value on all others.
|
||||
attr_accessor :response
|
||||
|
||||
# A flag that can be set a behavior that will cause this resource to be
|
||||
# encoded and sent up along with an update of its parent resource. This is
|
||||
# usually not desirable because resources are updated individually on their
|
||||
@ -61,8 +54,8 @@ module Stripe
|
||||
end
|
||||
|
||||
def refresh
|
||||
self.response, opts = request(:get, resource_url, @retrieve_params)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:get, resource_url, @retrieve_params)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def self.retrieve(id, opts={})
|
||||
|
@ -5,8 +5,8 @@ module Stripe
|
||||
extend Stripe::APIOperations::List
|
||||
|
||||
def verify(params={}, opts={})
|
||||
self.response, opts = request(:post, resource_url + '/verify', params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, resource_url + '/verify', params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def resource_url
|
||||
|
@ -20,41 +20,41 @@ module Stripe
|
||||
# from the server
|
||||
self.refresh
|
||||
else
|
||||
self.response, opts = request(:post, refund_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, refund_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
end
|
||||
|
||||
def capture(params={}, opts={})
|
||||
self.response, opts = request(:post, capture_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, capture_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def update_dispute(params={}, opts={})
|
||||
self.response, opts = request(:post, dispute_url, params, opts)
|
||||
initialize_from({ :dispute => response.data }, opts, true)
|
||||
resp, opts = request(:post, dispute_url, params, opts)
|
||||
initialize_from({ :dispute => resp.data }, opts, true)
|
||||
dispute
|
||||
end
|
||||
|
||||
def close_dispute(params={}, opts={})
|
||||
self.response, opts = request(:post, close_dispute_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, close_dispute_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def mark_as_fraudulent
|
||||
params = {
|
||||
:fraud_details => { :user_report => 'fraudulent' }
|
||||
}
|
||||
self.response, opts = request(:post, resource_url, params)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, resource_url, params)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def mark_as_safe
|
||||
params = {
|
||||
:fraud_details => { :user_report => 'safe' }
|
||||
}
|
||||
self.response, opts = request(:post, resource_url, params)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, resource_url, params)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -38,25 +38,25 @@ module Stripe
|
||||
end
|
||||
|
||||
def cancel_subscription(params={}, opts={})
|
||||
self.response, opts = request(:delete, subscription_url, params, opts)
|
||||
initialize_from({ :subscription => response.data }, opts, true)
|
||||
resp, opts = request(:delete, subscription_url, params, opts)
|
||||
initialize_from({ :subscription => resp.data }, opts, true)
|
||||
subscription
|
||||
end
|
||||
|
||||
def update_subscription(params={}, opts={})
|
||||
self.response, opts = request(:post, subscription_url, params, opts)
|
||||
initialize_from({ :subscription => response.data }, opts, true)
|
||||
resp, opts = request(:post, subscription_url, params, opts)
|
||||
initialize_from({ :subscription => resp.data }, opts, true)
|
||||
subscription
|
||||
end
|
||||
|
||||
def create_subscription(params={}, opts={})
|
||||
self.response, opts = request(:post, subscriptions_url, params, opts)
|
||||
initialize_from({ :subscription => response.data }, opts, true)
|
||||
resp, opts = request(:post, subscriptions_url, params, opts)
|
||||
initialize_from({ :subscription => resp.data }, opts, true)
|
||||
subscription
|
||||
end
|
||||
|
||||
def delete_discount
|
||||
self.response, opts = request(:delete, discount_url)
|
||||
resp, opts = request(:delete, discount_url)
|
||||
initialize_from({ :discount => nil }, opts, true)
|
||||
end
|
||||
|
||||
|
@ -5,8 +5,8 @@ module Stripe
|
||||
include Stripe::APIOperations::Save
|
||||
|
||||
def close(params={}, opts={})
|
||||
self.response, opts = request(:post, close_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, close_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def close_url
|
||||
|
@ -6,12 +6,12 @@ module Stripe
|
||||
|
||||
def self.upcoming(params, opts={})
|
||||
resp, opts = request(:get, upcoming_url, params, opts)
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
|
||||
def pay(opts={})
|
||||
self.response, opts = request(:post, pay_url, {}, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, pay_url, {}, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -10,10 +10,6 @@ module Stripe
|
||||
# expansions, and predicates as a user pages through resources.
|
||||
attr_accessor :filters
|
||||
|
||||
# Response contains a StripeResponse object that has some basic information
|
||||
# about the response that conveyed the list resource.
|
||||
attr_accessor :response
|
||||
|
||||
# An empty list object. This is returned from +next+ when we know that
|
||||
# there isn't a next page in order to replicate the behavior of the API
|
||||
# when it attempts to return a page beyond the last.
|
||||
@ -69,7 +65,7 @@ module Stripe
|
||||
def retrieve(id, opts={})
|
||||
id, retrieve_params = Util.normalize_id(id)
|
||||
resp, opts = request(:get,"#{resource_url}/#{CGI.escape(id)}", retrieve_params, opts)
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
|
||||
# Fetches the next page in the resource list (if there is one).
|
||||
|
@ -5,13 +5,13 @@ module Stripe
|
||||
include Stripe::APIOperations::Save
|
||||
|
||||
def pay(params, opts={})
|
||||
self.response, opts = request(:post, pay_url, params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, pay_url, params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
|
||||
def return_order(params, opts={})
|
||||
resp, opts = request(:post, returns_url, params, opts)
|
||||
Util.convert_to_stripe_object(resp.data, opts, response: resp)
|
||||
Util.convert_to_stripe_object(resp.data, opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -4,8 +4,8 @@ module Stripe
|
||||
include Stripe::APIOperations::Save
|
||||
|
||||
def verify(params={}, opts={})
|
||||
self.response, opts = request(:post, resource_url + '/verify', params, opts)
|
||||
initialize_from(response.data, opts)
|
||||
resp, opts = request(:post, resource_url + '/verify', params, opts)
|
||||
initialize_from(resp.data, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
20
lib/stripe/stripe_client.rb
Normal file
20
lib/stripe/stripe_client.rb
Normal file
@ -0,0 +1,20 @@
|
||||
module Stripe
|
||||
class StripeClient
|
||||
def initialize(conn)
|
||||
self.conn = conn
|
||||
end
|
||||
|
||||
def request(&block)
|
||||
res = block.call
|
||||
[res, Thread.local[:stripe_last_response]]
|
||||
end
|
||||
|
||||
def set_last_response(resp)
|
||||
Thread.local[:stripe_last_response] = resp
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :conn
|
||||
end
|
||||
end
|
@ -18,17 +18,16 @@ module Stripe
|
||||
# The Stripe request ID of the response.
|
||||
attr_accessor :request_id
|
||||
|
||||
# Initializes a StripeResponse object from a RestClient HTTP response
|
||||
# object.
|
||||
# Initializes a StripeResponse object from a Faraday HTTP response object.
|
||||
#
|
||||
# This may throw JSON::ParserError if the response body is not valid JSON.
|
||||
def self.from_rest_client_response(http_resp)
|
||||
def self.from_faraday_response(http_resp)
|
||||
resp = StripeResponse.new
|
||||
resp.data = JSON.parse(http_resp.body, symbolize_names: true)
|
||||
resp.http_body = http_resp.body
|
||||
resp.http_headers = http_resp.headers
|
||||
resp.http_status = http_resp.code
|
||||
resp.request_id = http_resp.headers[:request_id]
|
||||
resp.http_status = http_resp.status
|
||||
resp.request_id = http_resp.headers["Request-Id"]
|
||||
resp
|
||||
end
|
||||
end
|
||||
|
@ -5,8 +5,8 @@ module Stripe
|
||||
include Stripe::APIOperations::Save
|
||||
|
||||
def cancel
|
||||
self.response, api_key = self.request(:post, cancel_url)
|
||||
initialize_from(response.data, api_key)
|
||||
resp, api_key = self.request(:post, cancel_url)
|
||||
initialize_from(resp.data, api_key)
|
||||
end
|
||||
|
||||
def cancel_url
|
||||
|
@ -71,10 +71,8 @@ module Stripe
|
||||
# * +data+ - Hash of fields and values to be converted into a StripeObject.
|
||||
# * +opts+ - Options for +StripeObject+ like an API key that will be reused
|
||||
# on subsequent API calls.
|
||||
# * +response+ - An object containing information about the API response
|
||||
# that produced the data which is hydrating the StripeObject.
|
||||
def self.convert_to_stripe_object(data, opts, other_opts = {})
|
||||
obj = case data
|
||||
def self.convert_to_stripe_object(data, opts)
|
||||
case data
|
||||
when Array
|
||||
data.map { |i| convert_to_stripe_object(i, opts) }
|
||||
when Hash
|
||||
@ -83,14 +81,6 @@ module Stripe
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
case obj
|
||||
when APIResource, ListObject
|
||||
# Change this to an optional parameter when we drop 1.9 support.
|
||||
obj.response = other_opts[:response]
|
||||
end
|
||||
|
||||
obj
|
||||
end
|
||||
|
||||
def self.file_readable(file)
|
||||
|
@ -13,7 +13,7 @@ spec = Gem::Specification.new do |s|
|
||||
s.homepage = 'https://stripe.com/docs/api/ruby'
|
||||
s.license = 'MIT'
|
||||
|
||||
s.add_dependency('rest-client', '>= 1.4', '< 4.0')
|
||||
s.add_dependency('faraday', '~> 0')
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.test_files = `git ls-files -- test/*`.split("\n")
|
||||
|
@ -167,17 +167,6 @@ module Stripe
|
||||
assert_equal 'Invalid response object from API: "{\"error\":\"foo\"}" (HTTP response code was 500)', e.message
|
||||
end
|
||||
|
||||
should "set response on error" do
|
||||
response = make_response('{"error": { "message": "foo"}}', 500)
|
||||
@mock.expects(:post).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
|
||||
|
||||
e = assert_raises Stripe::APIError do
|
||||
Stripe::Charge.create
|
||||
end
|
||||
|
||||
assert_equal 500, e.response.http_status
|
||||
end
|
||||
|
||||
should "have default open and read timeouts" do
|
||||
assert_equal Stripe.open_timeout, 30
|
||||
assert_equal Stripe.read_timeout, 80
|
||||
@ -321,8 +310,11 @@ module Stripe
|
||||
end
|
||||
|
||||
should "a 429 should give a RateLimitError with http status, body, and JSON body" do
|
||||
stub_request(:post, "#{Stripe.api_base}/v1/charges").
|
||||
to_return(body: JSON.generate(make_missing_id_error), status: 429)
|
||||
error = make_rate_limit_error
|
||||
response = make_response(error, 429)
|
||||
@mock.expects(:get).once.raises(
|
||||
Faraday::ClientError.new(error[:error][:message], response)
|
||||
)
|
||||
begin
|
||||
Stripe::Charge.create
|
||||
rescue Stripe::RateLimitError => e
|
||||
@ -815,16 +807,19 @@ module Stripe
|
||||
Stripe.stubs(:max_network_retries).returns(2)
|
||||
end
|
||||
|
||||
should 'retry on a low-level network error' do
|
||||
assert Stripe.should_retry?(Errno::ECONNREFUSED.new, 0)
|
||||
should 'retry on timeout' do
|
||||
assert Stripe.should_retry?(Faraday::TimeoutError.new(""), 0)
|
||||
end
|
||||
|
||||
should 'retry on timeout' do
|
||||
assert Stripe.should_retry?(RestClient::RequestTimeout.new, 0)
|
||||
should 'retry on a failed connection' do
|
||||
assert Stripe.should_retry?(Faraday::ConnectionFailed.new(""), 0)
|
||||
end
|
||||
|
||||
should 'retry on a conflict' do
|
||||
assert Stripe.should_retry?(RestClient::Conflict.new, 0)
|
||||
error = make_rate_limit_error
|
||||
response = make_response(error, 429)
|
||||
e = Faraday::ClientError.new(error[:error][:message], response)
|
||||
assert Stripe.should_retry?(e, 0)
|
||||
end
|
||||
|
||||
should 'not retry at maximum count' do
|
||||
@ -832,7 +827,7 @@ module Stripe
|
||||
end
|
||||
|
||||
should 'not retry on a certificate validation error' do
|
||||
refute Stripe.should_retry?(RestClient::SSLCertificateNotVerified.new('message'), 0)
|
||||
refute Stripe.should_retry?(Faraday::SSLError.new(""), 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2,13 +2,13 @@ require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
module Stripe
|
||||
class StripeResponseTest < Test::Unit::TestCase
|
||||
context ".from_rest_client_response" do
|
||||
context ".from_faraday_response" do
|
||||
should "converts to StripeResponse" do
|
||||
body = '{"foo": "bar"}'
|
||||
headers = { :request_id => "request-id" }
|
||||
|
||||
http_resp = make_response(body, 200, headers: headers)
|
||||
resp = StripeResponse.from_rest_client_response(http_resp)
|
||||
resp = StripeResponse.from_faraday_response(http_resp)
|
||||
|
||||
assert_equal JSON.parse(body, symbolize_names: true), resp.data
|
||||
assert_equal body, resp.http_body
|
||||
|
@ -142,24 +142,6 @@ module Stripe
|
||||
assert_equal [1, 2, 3], obj
|
||||
end
|
||||
|
||||
should "#convert_to_stripe_object should add a response to APIResource" do
|
||||
resp = StripeResponse.new
|
||||
obj = Util.convert_to_stripe_object({ :object => "account" }, {}, response: resp)
|
||||
assert_equal resp, obj.response
|
||||
end
|
||||
|
||||
should "#convert_to_stripe_object should add a response to ListObject" do
|
||||
resp = StripeResponse.new
|
||||
obj = Util.convert_to_stripe_object({ :object => "list" }, {}, response: resp)
|
||||
assert_equal resp, obj.response
|
||||
end
|
||||
|
||||
should "#convert_to_stripe_object should not add a response to other types" do
|
||||
resp = StripeResponse.new
|
||||
obj = Util.convert_to_stripe_object({ :foo => "bar" }, {}, response: resp)
|
||||
refute obj.respond_to?(:response)
|
||||
end
|
||||
|
||||
should "#array_to_hash should convert an array into a hash with integer keys" do
|
||||
assert_equal({"0" => 1, "1" => 2, "2" => 3}, Util.array_to_hash([1, 2, 3]))
|
||||
end
|
||||
|
@ -512,6 +512,15 @@ module Stripe
|
||||
}
|
||||
end
|
||||
|
||||
def make_error(type, message)
|
||||
{
|
||||
:error => {
|
||||
:type => type,
|
||||
:message => message,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def make_invalid_api_key_error
|
||||
{
|
||||
:error => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user