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.
Files changed (46) hide show
  1. checksums.yaml +13 -5
  2. data/.gitignore +8 -8
  3. data/.travis.yml +6 -6
  4. data/Gemfile +1 -1
  5. data/README.md +171 -168
  6. data/Rakefile +8 -8
  7. data/dwolla-ruby.gemspec +27 -27
  8. data/examples/balance.rb +15 -15
  9. data/examples/contacts.rb +32 -32
  10. data/examples/fundingSources.rb +39 -39
  11. data/examples/oauth.rb +50 -50
  12. data/examples/offsiteGateway.rb +31 -31
  13. data/examples/transactions.rb +38 -38
  14. data/examples/users.rb +30 -30
  15. data/gemfiles/json.gemfile +2 -2
  16. data/lib/dwolla.rb +326 -326
  17. data/lib/dwolla/accounts.rb +27 -27
  18. data/lib/dwolla/balance.rb +15 -15
  19. data/lib/dwolla/contacts.rb +30 -30
  20. data/lib/dwolla/errors/api_connection_error.rb +3 -3
  21. data/lib/dwolla/errors/api_error.rb +3 -3
  22. data/lib/dwolla/errors/authentication_error.rb +3 -3
  23. data/lib/dwolla/errors/dwolla_error.rb +19 -19
  24. data/lib/dwolla/errors/invalid_request_error.rb +10 -10
  25. data/lib/dwolla/errors/missing_parameter_error.rb +3 -3
  26. data/lib/dwolla/exceptions.rb +4 -4
  27. data/lib/dwolla/funding_sources.rb +65 -65
  28. data/lib/dwolla/json.rb +20 -20
  29. data/lib/dwolla/masspay.rb +52 -52
  30. data/lib/dwolla/oauth.rb +75 -75
  31. data/lib/dwolla/offsite_gateway.rb +154 -154
  32. data/lib/dwolla/requests.rb +56 -56
  33. data/lib/dwolla/transactions.rb +56 -56
  34. data/lib/dwolla/users.rb +39 -39
  35. data/lib/dwolla/version.rb +3 -3
  36. data/test/test_accounts.rb +18 -18
  37. data/test/test_balance.rb +9 -9
  38. data/test/test_contacts.rb +19 -19
  39. data/test/test_funding_sources.rb +64 -64
  40. data/test/test_masspay.rb +47 -47
  41. data/test/test_oauth.rb +30 -30
  42. data/test/test_offsite_gateway.rb +57 -57
  43. data/test/test_requests.rb +29 -29
  44. data/test/test_transactions.rb +51 -51
  45. data/test/test_users.rb +33 -33
  46. metadata +15 -15
@@ -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