dwolla-ruby 2.6.1 → 2.6.2
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.
- checksums.yaml +13 -5
- data/.gitignore +8 -8
- data/.travis.yml +6 -6
- data/Gemfile +1 -1
- data/README.md +171 -168
- data/Rakefile +8 -8
- data/dwolla-ruby.gemspec +27 -27
- data/examples/balance.rb +15 -15
- data/examples/contacts.rb +32 -32
- data/examples/fundingSources.rb +39 -39
- data/examples/oauth.rb +50 -50
- data/examples/offsiteGateway.rb +31 -31
- data/examples/transactions.rb +38 -38
- data/examples/users.rb +30 -30
- data/gemfiles/json.gemfile +2 -2
- data/lib/dwolla.rb +326 -326
- data/lib/dwolla/accounts.rb +27 -27
- data/lib/dwolla/balance.rb +15 -15
- data/lib/dwolla/contacts.rb +30 -30
- data/lib/dwolla/errors/api_connection_error.rb +3 -3
- data/lib/dwolla/errors/api_error.rb +3 -3
- data/lib/dwolla/errors/authentication_error.rb +3 -3
- data/lib/dwolla/errors/dwolla_error.rb +19 -19
- data/lib/dwolla/errors/invalid_request_error.rb +10 -10
- data/lib/dwolla/errors/missing_parameter_error.rb +3 -3
- data/lib/dwolla/exceptions.rb +4 -4
- data/lib/dwolla/funding_sources.rb +65 -65
- data/lib/dwolla/json.rb +20 -20
- data/lib/dwolla/masspay.rb +52 -52
- data/lib/dwolla/oauth.rb +75 -75
- data/lib/dwolla/offsite_gateway.rb +154 -154
- data/lib/dwolla/requests.rb +56 -56
- data/lib/dwolla/transactions.rb +56 -56
- data/lib/dwolla/users.rb +39 -39
- data/lib/dwolla/version.rb +3 -3
- data/test/test_accounts.rb +18 -18
- data/test/test_balance.rb +9 -9
- data/test/test_contacts.rb +19 -19
- data/test/test_funding_sources.rb +64 -64
- data/test/test_masspay.rb +47 -47
- data/test/test_oauth.rb +30 -30
- data/test/test_offsite_gateway.rb +57 -57
- data/test/test_requests.rb +29 -29
- data/test/test_transactions.rb +51 -51
- data/test/test_users.rb +33 -33
- metadata +15 -15
data/gemfiles/json.gemfile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
gemspec :path => File.join(File.dirname(__FILE__), "..")
|
1
|
+
source "https://rubygems.org"
|
2
|
+
gemspec :path => File.join(File.dirname(__FILE__), "..")
|
3
3
|
gem "json"
|
data/lib/dwolla.rb
CHANGED
@@ -1,326 +1,326 @@
|
|
1
|
-
# Dwolla Ruby API Wrapper
|
2
|
-
# Heavily based off Stripe's Ruby Gem
|
3
|
-
# API spec at https://developers.dwolla.com
|
4
|
-
require 'openssl'
|
5
|
-
require 'rest_client'
|
6
|
-
require 'multi_json'
|
7
|
-
require 'addressable/uri'
|
8
|
-
|
9
|
-
# Version
|
10
|
-
require_relative 'dwolla/version'
|
11
|
-
|
12
|
-
# Resources
|
13
|
-
require_relative 'dwolla/json'
|
14
|
-
require_relative 'dwolla/transactions'
|
15
|
-
require_relative 'dwolla/requests'
|
16
|
-
require_relative 'dwolla/contacts'
|
17
|
-
require_relative 'dwolla/users'
|
18
|
-
require_relative 'dwolla/balance'
|
19
|
-
require_relative 'dwolla/funding_sources'
|
20
|
-
require_relative 'dwolla/oauth'
|
21
|
-
require_relative 'dwolla/offsite_gateway'
|
22
|
-
require_relative 'dwolla/accounts'
|
23
|
-
require_relative 'dwolla/masspay'
|
24
|
-
|
25
|
-
# Errors
|
26
|
-
require_relative 'dwolla/errors/dwolla_error'
|
27
|
-
require_relative 'dwolla/errors/api_connection_error'
|
28
|
-
require_relative 'dwolla/errors/api_error'
|
29
|
-
require_relative 'dwolla/errors/missing_parameter_error'
|
30
|
-
require_relative 'dwolla/errors/authentication_error'
|
31
|
-
require_relative 'dwolla/errors/invalid_request_error'
|
32
|
-
|
33
|
-
module Dwolla
|
34
|
-
@@api_key = nil
|
35
|
-
@@api_secret = nil
|
36
|
-
@@token = nil
|
37
|
-
@@api_base = '/oauth/rest'
|
38
|
-
@@verify_ssl_certs = true
|
39
|
-
@@api_version = nil
|
40
|
-
@@debug = false
|
41
|
-
@@sandbox = false
|
42
|
-
@@scope = 'send|transactions|balance|request|contacts|accountinfofull|funding'
|
43
|
-
|
44
|
-
def self.api_key=(api_key)
|
45
|
-
@@api_key = api_key
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.api_key
|
49
|
-
@@api_key
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.api_secret=(api_secret)
|
53
|
-
@@api_secret = api_secret
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.api_secret
|
57
|
-
@@api_secret
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.sandbox=(sandbox)
|
61
|
-
@@sandbox = sandbox
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.sandbox
|
65
|
-
@@sandbox
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.debug
|
69
|
-
@@debug
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.debug=(debug)
|
73
|
-
@@debug = debug
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.api_version=(api_version)
|
77
|
-
@@api_version = api_version
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.api_version
|
81
|
-
@@api_version
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.verify_ssl_certs=(verify_ssl_certs)
|
85
|
-
@@verify_ssl_certs = verify_ssl_certs
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.verify_ssl_certs
|
89
|
-
@@verify_ssl_certs
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.token=(token)
|
93
|
-
@@token = token
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.token
|
97
|
-
@@token
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.scope=(scope)
|
101
|
-
@@scope = scope
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.scope
|
105
|
-
@@scope
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.hostname
|
109
|
-
if not @@sandbox
|
110
|
-
return 'https://www.dwolla.com'
|
111
|
-
else
|
112
|
-
return 'https://uat.dwolla.com'
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.endpoint_url(endpoint)
|
117
|
-
self.hostname + @@api_base + endpoint
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.request(method, url, params={}, headers={}, oauth=true, parse_response=true, custom_url=false)
|
121
|
-
# if oauth is nil, assume default [true]
|
122
|
-
oauth = true if oauth.nil?
|
123
|
-
|
124
|
-
# figure out which auth to use
|
125
|
-
if oauth and not params[:oauth_token]
|
126
|
-
if not oauth.is_a?(TrueClass) # was token passed in the oauth param?
|
127
|
-
params = {
|
128
|
-
:oauth_token => oauth
|
129
|
-
}.merge(params)
|
130
|
-
else
|
131
|
-
raise AuthenticationError.new('No OAuth Token Provided.') unless token
|
132
|
-
params = {
|
133
|
-
:oauth_token => token
|
134
|
-
}.merge(params)
|
135
|
-
end
|
136
|
-
elsif oauth and params[:oauth_token]
|
137
|
-
raise AuthenticationError.new('No OAuth Token Provided.') unless params[:oauth_token]
|
138
|
-
else not oauth
|
139
|
-
raise AuthenticationError.new('No App Key & Secret Provided.') unless (api_key && api_secret)
|
140
|
-
params = {
|
141
|
-
:client_id => api_key,
|
142
|
-
:client_secret => api_secret
|
143
|
-
}.merge(params)
|
144
|
-
end
|
145
|
-
|
146
|
-
if !verify_ssl_certs
|
147
|
-
$stderr.puts "WARNING: Running without SSL cert verification."
|
148
|
-
else
|
149
|
-
ssl_opts = {
|
150
|
-
:use_ssl => true
|
151
|
-
}
|
152
|
-
end
|
153
|
-
|
154
|
-
uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
|
155
|
-
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
156
|
-
ua = {
|
157
|
-
:bindings_version => Dwolla::VERSION,
|
158
|
-
:lang => 'ruby',
|
159
|
-
:lang_version => lang_version,
|
160
|
-
:platform => RUBY_PLATFORM,
|
161
|
-
:publisher => 'dwolla',
|
162
|
-
:uname => uname
|
163
|
-
}
|
164
|
-
|
165
|
-
url = self.endpoint_url(url) unless custom_url
|
166
|
-
|
167
|
-
case method.to_s.downcase.to_sym
|
168
|
-
when :get
|
169
|
-
# Make params into GET parameters
|
170
|
-
if params && params.count > 0
|
171
|
-
uri = Addressable::URI.new
|
172
|
-
uri.query_values = params
|
173
|
-
url += '?' + uri.query
|
174
|
-
end
|
175
|
-
payload = nil
|
176
|
-
else
|
177
|
-
payload = JSON.dump(params)
|
178
|
-
end
|
179
|
-
|
180
|
-
begin
|
181
|
-
headers = { :x_dwolla_client_user_agent => Dwolla::JSON.dump(ua) }.merge(headers)
|
182
|
-
rescue => e
|
183
|
-
headers = {
|
184
|
-
:x_dwolla_client_raw_user_agent => ua.inspect,
|
185
|
-
:error => "#{e} (#{e.class})"
|
186
|
-
}.merge(headers)
|
187
|
-
end
|
188
|
-
|
189
|
-
headers = {
|
190
|
-
:user_agent => "Dwolla Ruby API Wrapper/#{Dwolla::VERSION}",
|
191
|
-
:content_type => 'application/json'
|
192
|
-
}.merge(headers)
|
193
|
-
|
194
|
-
if self.api_version
|
195
|
-
headers[:dwolla_version] = self.api_version
|
196
|
-
end
|
197
|
-
|
198
|
-
opts = {
|
199
|
-
:method => method,
|
200
|
-
:url => url,
|
201
|
-
:headers => headers,
|
202
|
-
:open_timeout => 30,
|
203
|
-
:payload => payload,
|
204
|
-
:timeout => 80
|
205
|
-
}.merge(ssl_opts)
|
206
|
-
|
207
|
-
if self.debug
|
208
|
-
if self.sandbox
|
209
|
-
puts "[DWOLLA SANDBOX MODE OPERATION]"
|
210
|
-
end
|
211
|
-
|
212
|
-
puts "Firing request with options and headers:"
|
213
|
-
puts opts
|
214
|
-
puts headers
|
215
|
-
end
|
216
|
-
|
217
|
-
begin
|
218
|
-
response = execute_request(opts)
|
219
|
-
rescue SocketError => e
|
220
|
-
self.handle_restclient_error(e)
|
221
|
-
rescue NoMethodError => e
|
222
|
-
# Work around RestClient bug
|
223
|
-
if e.message =~ /\WRequestFailed\W/
|
224
|
-
e = APIConnectionError.new('Unexpected HTTP response code')
|
225
|
-
self.handle_restclient_error(e)
|
226
|
-
else
|
227
|
-
raise
|
228
|
-
end
|
229
|
-
rescue RestClient::ExceptionWithResponse => e
|
230
|
-
if rcode = e.http_code and rbody = e.http_body
|
231
|
-
self.handle_api_error(rcode, rbody)
|
232
|
-
else
|
233
|
-
self.handle_restclient_error(e)
|
234
|
-
end
|
235
|
-
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
236
|
-
self.handle_restclient_error(e)
|
237
|
-
end
|
238
|
-
|
239
|
-
rbody = response.body
|
240
|
-
rcode = response.code
|
241
|
-
|
242
|
-
if self.debug
|
243
|
-
puts "Raw response headers received:"
|
244
|
-
puts headers
|
245
|
-
puts "Raw response body received:"
|
246
|
-
puts rbody
|
247
|
-
end
|
248
|
-
|
249
|
-
resp = self.extract_json(rbody, rcode)
|
250
|
-
|
251
|
-
if parse_response
|
252
|
-
return self.parse_response(resp)
|
253
|
-
else
|
254
|
-
return resp
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
private
|
259
|
-
|
260
|
-
def self.execute_request(opts)
|
261
|
-
RestClient::Request.execute(opts)
|
262
|
-
end
|
263
|
-
|
264
|
-
def self.extract_json(rbody, rcode)
|
265
|
-
begin
|
266
|
-
resp = Dwolla::JSON.load(rbody)
|
267
|
-
rescue MultiJson::DecodeError
|
268
|
-
raise APIError.new("There was an error parsing Dwolla's API response: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
269
|
-
end
|
270
|
-
|
271
|
-
return resp
|
272
|
-
end
|
273
|
-
|
274
|
-
def self.parse_response(resp)
|
275
|
-
raise APIError.new(resp['Message']) unless resp.has_key?('Success') and resp['Success'] == true
|
276
|
-
|
277
|
-
return resp['Response']
|
278
|
-
end
|
279
|
-
|
280
|
-
def self.handle_api_error(rcode, rbody)
|
281
|
-
begin
|
282
|
-
error_obj = Dwolla::JSON.load(rbody)
|
283
|
-
error = error_obj[:error] or raise DwollaError.new # escape from parsing
|
284
|
-
rescue MultiJson::DecodeError, DwollaError
|
285
|
-
raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
286
|
-
end
|
287
|
-
|
288
|
-
case rcode
|
289
|
-
when 400, 404 then
|
290
|
-
raise invalid_request_error(error, rcode, rbody, error_obj)
|
291
|
-
when 401
|
292
|
-
raise authentication_error(error, rcode, rbody, error_obj)
|
293
|
-
else
|
294
|
-
raise api_error(error, rcode, rbody, error_obj)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
def self.invalid_request_error(error, rcode, rbody, error_obj)
|
299
|
-
InvalidRequestError.new(error[:message], error[:param], rcode, rbody, error_obj)
|
300
|
-
end
|
301
|
-
|
302
|
-
def self.authentication_error(error, rcode, rbody, error_obj)
|
303
|
-
AuthenticationError.new(error[:message], rcode, rbody, error_obj)
|
304
|
-
end
|
305
|
-
|
306
|
-
def self.api_error(error, rcode, rbody, error_obj)
|
307
|
-
APIError.new(error[:message], rcode, rbody, error_obj)
|
308
|
-
end
|
309
|
-
|
310
|
-
def self.handle_restclient_error(e)
|
311
|
-
case e
|
312
|
-
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
313
|
-
message = "Could not connect to Dwolla (#{@@api_base}). Please check your internet connection and try again. If this problem persists, you should check Dwolla's service status at https://twitter.com/Dwolla, or let us know at support@Dwolla.com."
|
314
|
-
when RestClient::SSLCertificateNotVerified
|
315
|
-
message = "Could not verify Dwolla's SSL certificate. If this problem persists, let us know at support@dwolla.com."
|
316
|
-
when SocketError
|
317
|
-
message = "Unexpected error communicating when trying to connect to Dwolla. If this problem persists, let us know at support@dwolla.com."
|
318
|
-
else
|
319
|
-
message = "Unexpected error communicating with Dwolla. If this problem persists, let us know at support@dwolla.com."
|
320
|
-
end
|
321
|
-
|
322
|
-
message += "\n\n(Network error: #{e.message})"
|
323
|
-
|
324
|
-
raise APIConnectionError.new(message)
|
325
|
-
end
|
326
|
-
end
|
1
|
+
# Dwolla Ruby API Wrapper
|
2
|
+
# Heavily based off Stripe's Ruby Gem
|
3
|
+
# API spec at https://developers.dwolla.com
|
4
|
+
require 'openssl'
|
5
|
+
require 'rest_client'
|
6
|
+
require 'multi_json'
|
7
|
+
require 'addressable/uri'
|
8
|
+
|
9
|
+
# Version
|
10
|
+
require_relative 'dwolla/version'
|
11
|
+
|
12
|
+
# Resources
|
13
|
+
require_relative 'dwolla/json'
|
14
|
+
require_relative 'dwolla/transactions'
|
15
|
+
require_relative 'dwolla/requests'
|
16
|
+
require_relative 'dwolla/contacts'
|
17
|
+
require_relative 'dwolla/users'
|
18
|
+
require_relative 'dwolla/balance'
|
19
|
+
require_relative 'dwolla/funding_sources'
|
20
|
+
require_relative 'dwolla/oauth'
|
21
|
+
require_relative 'dwolla/offsite_gateway'
|
22
|
+
require_relative 'dwolla/accounts'
|
23
|
+
require_relative 'dwolla/masspay'
|
24
|
+
|
25
|
+
# Errors
|
26
|
+
require_relative 'dwolla/errors/dwolla_error'
|
27
|
+
require_relative 'dwolla/errors/api_connection_error'
|
28
|
+
require_relative 'dwolla/errors/api_error'
|
29
|
+
require_relative 'dwolla/errors/missing_parameter_error'
|
30
|
+
require_relative 'dwolla/errors/authentication_error'
|
31
|
+
require_relative 'dwolla/errors/invalid_request_error'
|
32
|
+
|
33
|
+
module Dwolla
|
34
|
+
@@api_key = nil
|
35
|
+
@@api_secret = nil
|
36
|
+
@@token = nil
|
37
|
+
@@api_base = '/oauth/rest'
|
38
|
+
@@verify_ssl_certs = true
|
39
|
+
@@api_version = nil
|
40
|
+
@@debug = false
|
41
|
+
@@sandbox = false
|
42
|
+
@@scope = 'send|transactions|balance|request|contacts|accountinfofull|funding'
|
43
|
+
|
44
|
+
def self.api_key=(api_key)
|
45
|
+
@@api_key = api_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.api_key
|
49
|
+
@@api_key
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.api_secret=(api_secret)
|
53
|
+
@@api_secret = api_secret
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.api_secret
|
57
|
+
@@api_secret
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.sandbox=(sandbox)
|
61
|
+
@@sandbox = sandbox
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.sandbox
|
65
|
+
@@sandbox
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.debug
|
69
|
+
@@debug
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.debug=(debug)
|
73
|
+
@@debug = debug
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.api_version=(api_version)
|
77
|
+
@@api_version = api_version
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.api_version
|
81
|
+
@@api_version
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.verify_ssl_certs=(verify_ssl_certs)
|
85
|
+
@@verify_ssl_certs = verify_ssl_certs
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.verify_ssl_certs
|
89
|
+
@@verify_ssl_certs
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.token=(token)
|
93
|
+
@@token = token
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.token
|
97
|
+
@@token
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.scope=(scope)
|
101
|
+
@@scope = scope
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.scope
|
105
|
+
@@scope
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.hostname
|
109
|
+
if not @@sandbox
|
110
|
+
return 'https://www.dwolla.com'
|
111
|
+
else
|
112
|
+
return 'https://uat.dwolla.com'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.endpoint_url(endpoint)
|
117
|
+
self.hostname + @@api_base + endpoint
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.request(method, url, params={}, headers={}, oauth=true, parse_response=true, custom_url=false)
|
121
|
+
# if oauth is nil, assume default [true]
|
122
|
+
oauth = true if oauth.nil?
|
123
|
+
|
124
|
+
# figure out which auth to use
|
125
|
+
if oauth and not params[:oauth_token]
|
126
|
+
if not oauth.is_a?(TrueClass) # was token passed in the oauth param?
|
127
|
+
params = {
|
128
|
+
:oauth_token => oauth
|
129
|
+
}.merge(params)
|
130
|
+
else
|
131
|
+
raise AuthenticationError.new('No OAuth Token Provided.') unless token
|
132
|
+
params = {
|
133
|
+
:oauth_token => token
|
134
|
+
}.merge(params)
|
135
|
+
end
|
136
|
+
elsif oauth and params[:oauth_token]
|
137
|
+
raise AuthenticationError.new('No OAuth Token Provided.') unless params[:oauth_token]
|
138
|
+
else not oauth
|
139
|
+
raise AuthenticationError.new('No App Key & Secret Provided.') unless (api_key && api_secret)
|
140
|
+
params = {
|
141
|
+
:client_id => api_key,
|
142
|
+
:client_secret => api_secret
|
143
|
+
}.merge(params)
|
144
|
+
end
|
145
|
+
|
146
|
+
if !verify_ssl_certs
|
147
|
+
$stderr.puts "WARNING: Running without SSL cert verification."
|
148
|
+
else
|
149
|
+
ssl_opts = {
|
150
|
+
:use_ssl => true
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
|
155
|
+
lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
|
156
|
+
ua = {
|
157
|
+
:bindings_version => Dwolla::VERSION,
|
158
|
+
:lang => 'ruby',
|
159
|
+
:lang_version => lang_version,
|
160
|
+
:platform => RUBY_PLATFORM,
|
161
|
+
:publisher => 'dwolla',
|
162
|
+
:uname => uname
|
163
|
+
}
|
164
|
+
|
165
|
+
url = self.endpoint_url(url) unless custom_url
|
166
|
+
|
167
|
+
case method.to_s.downcase.to_sym
|
168
|
+
when :get
|
169
|
+
# Make params into GET parameters
|
170
|
+
if params && params.count > 0
|
171
|
+
uri = Addressable::URI.new
|
172
|
+
uri.query_values = params
|
173
|
+
url += '?' + uri.query
|
174
|
+
end
|
175
|
+
payload = nil
|
176
|
+
else
|
177
|
+
payload = JSON.dump(params)
|
178
|
+
end
|
179
|
+
|
180
|
+
begin
|
181
|
+
headers = { :x_dwolla_client_user_agent => Dwolla::JSON.dump(ua) }.merge(headers)
|
182
|
+
rescue => e
|
183
|
+
headers = {
|
184
|
+
:x_dwolla_client_raw_user_agent => ua.inspect,
|
185
|
+
:error => "#{e} (#{e.class})"
|
186
|
+
}.merge(headers)
|
187
|
+
end
|
188
|
+
|
189
|
+
headers = {
|
190
|
+
:user_agent => "Dwolla Ruby API Wrapper/#{Dwolla::VERSION}",
|
191
|
+
:content_type => 'application/json'
|
192
|
+
}.merge(headers)
|
193
|
+
|
194
|
+
if self.api_version
|
195
|
+
headers[:dwolla_version] = self.api_version
|
196
|
+
end
|
197
|
+
|
198
|
+
opts = {
|
199
|
+
:method => method,
|
200
|
+
:url => url,
|
201
|
+
:headers => headers,
|
202
|
+
:open_timeout => 30,
|
203
|
+
:payload => payload,
|
204
|
+
:timeout => 80
|
205
|
+
}.merge(ssl_opts)
|
206
|
+
|
207
|
+
if self.debug
|
208
|
+
if self.sandbox
|
209
|
+
puts "[DWOLLA SANDBOX MODE OPERATION]"
|
210
|
+
end
|
211
|
+
|
212
|
+
puts "Firing request with options and headers:"
|
213
|
+
puts opts
|
214
|
+
puts headers
|
215
|
+
end
|
216
|
+
|
217
|
+
begin
|
218
|
+
response = execute_request(opts)
|
219
|
+
rescue SocketError => e
|
220
|
+
self.handle_restclient_error(e)
|
221
|
+
rescue NoMethodError => e
|
222
|
+
# Work around RestClient bug
|
223
|
+
if e.message =~ /\WRequestFailed\W/
|
224
|
+
e = APIConnectionError.new('Unexpected HTTP response code')
|
225
|
+
self.handle_restclient_error(e)
|
226
|
+
else
|
227
|
+
raise
|
228
|
+
end
|
229
|
+
rescue RestClient::ExceptionWithResponse => e
|
230
|
+
if rcode = e.http_code and rbody = e.http_body
|
231
|
+
self.handle_api_error(rcode, rbody)
|
232
|
+
else
|
233
|
+
self.handle_restclient_error(e)
|
234
|
+
end
|
235
|
+
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
236
|
+
self.handle_restclient_error(e)
|
237
|
+
end
|
238
|
+
|
239
|
+
rbody = response.body
|
240
|
+
rcode = response.code
|
241
|
+
|
242
|
+
if self.debug
|
243
|
+
puts "Raw response headers received:"
|
244
|
+
puts headers
|
245
|
+
puts "Raw response body received:"
|
246
|
+
puts rbody
|
247
|
+
end
|
248
|
+
|
249
|
+
resp = self.extract_json(rbody, rcode)
|
250
|
+
|
251
|
+
if parse_response
|
252
|
+
return self.parse_response(resp)
|
253
|
+
else
|
254
|
+
return resp
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
def self.execute_request(opts)
|
261
|
+
RestClient::Request.execute(opts)
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.extract_json(rbody, rcode)
|
265
|
+
begin
|
266
|
+
resp = Dwolla::JSON.load(rbody)
|
267
|
+
rescue MultiJson::DecodeError
|
268
|
+
raise APIError.new("There was an error parsing Dwolla's API response: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
269
|
+
end
|
270
|
+
|
271
|
+
return resp
|
272
|
+
end
|
273
|
+
|
274
|
+
def self.parse_response(resp)
|
275
|
+
raise APIError.new(resp['Message']) unless resp.has_key?('Success') and resp['Success'] == true
|
276
|
+
|
277
|
+
return resp['Response']
|
278
|
+
end
|
279
|
+
|
280
|
+
def self.handle_api_error(rcode, rbody)
|
281
|
+
begin
|
282
|
+
error_obj = Dwolla::JSON.load(rbody)
|
283
|
+
error = error_obj[:error] or raise DwollaError.new # escape from parsing
|
284
|
+
rescue MultiJson::DecodeError, DwollaError
|
285
|
+
raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
286
|
+
end
|
287
|
+
|
288
|
+
case rcode
|
289
|
+
when 400, 404 then
|
290
|
+
raise invalid_request_error(error, rcode, rbody, error_obj)
|
291
|
+
when 401
|
292
|
+
raise authentication_error(error, rcode, rbody, error_obj)
|
293
|
+
else
|
294
|
+
raise api_error(error, rcode, rbody, error_obj)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.invalid_request_error(error, rcode, rbody, error_obj)
|
299
|
+
InvalidRequestError.new(error[:message], error[:param], rcode, rbody, error_obj)
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.authentication_error(error, rcode, rbody, error_obj)
|
303
|
+
AuthenticationError.new(error[:message], rcode, rbody, error_obj)
|
304
|
+
end
|
305
|
+
|
306
|
+
def self.api_error(error, rcode, rbody, error_obj)
|
307
|
+
APIError.new(error[:message], rcode, rbody, error_obj)
|
308
|
+
end
|
309
|
+
|
310
|
+
def self.handle_restclient_error(e)
|
311
|
+
case e
|
312
|
+
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
313
|
+
message = "Could not connect to Dwolla (#{@@api_base}). Please check your internet connection and try again. If this problem persists, you should check Dwolla's service status at https://twitter.com/Dwolla, or let us know at support@Dwolla.com."
|
314
|
+
when RestClient::SSLCertificateNotVerified
|
315
|
+
message = "Could not verify Dwolla's SSL certificate. If this problem persists, let us know at support@dwolla.com."
|
316
|
+
when SocketError
|
317
|
+
message = "Unexpected error communicating when trying to connect to Dwolla. If this problem persists, let us know at support@dwolla.com."
|
318
|
+
else
|
319
|
+
message = "Unexpected error communicating with Dwolla. If this problem persists, let us know at support@dwolla.com."
|
320
|
+
end
|
321
|
+
|
322
|
+
message += "\n\n(Network error: #{e.message})"
|
323
|
+
|
324
|
+
raise APIConnectionError.new(message)
|
325
|
+
end
|
326
|
+
end
|