faraday 1.4.1 → 2.7.4

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +197 -3
  3. data/LICENSE.md +1 -1
  4. data/README.md +18 -16
  5. data/examples/client_spec.rb +67 -13
  6. data/examples/client_test.rb +80 -15
  7. data/lib/faraday/adapter/test.rb +117 -52
  8. data/lib/faraday/adapter.rb +5 -14
  9. data/lib/faraday/connection.rb +64 -119
  10. data/lib/faraday/encoders/nested_params_encoder.rb +13 -6
  11. data/lib/faraday/error.rb +3 -8
  12. data/lib/faraday/logging/formatter.rb +19 -2
  13. data/lib/faraday/middleware.rb +3 -1
  14. data/lib/faraday/middleware_registry.rb +17 -63
  15. data/lib/faraday/options/env.rb +31 -7
  16. data/lib/faraday/options/proxy_options.rb +4 -0
  17. data/lib/faraday/options/ssl_options.rb +11 -1
  18. data/lib/faraday/options.rb +3 -3
  19. data/lib/faraday/rack_builder.rb +23 -20
  20. data/lib/faraday/request/authorization.rb +37 -38
  21. data/lib/faraday/request/instrumentation.rb +2 -0
  22. data/lib/faraday/request/json.rb +55 -0
  23. data/lib/faraday/request/url_encoded.rb +5 -1
  24. data/lib/faraday/request.rb +12 -32
  25. data/lib/faraday/response/json.rb +54 -0
  26. data/lib/faraday/response/logger.rb +8 -4
  27. data/lib/faraday/response/raise_error.rb +9 -1
  28. data/lib/faraday/response.rb +10 -20
  29. data/lib/faraday/utils/headers.rb +7 -2
  30. data/lib/faraday/utils.rb +10 -5
  31. data/lib/faraday/version.rb +1 -1
  32. data/lib/faraday.rb +10 -31
  33. data/spec/faraday/adapter/test_spec.rb +182 -0
  34. data/spec/faraday/connection_spec.rb +177 -90
  35. data/spec/faraday/middleware_registry_spec.rb +31 -0
  36. data/spec/faraday/middleware_spec.rb +18 -0
  37. data/spec/faraday/options/env_spec.rb +8 -2
  38. data/spec/faraday/options/proxy_options_spec.rb +7 -0
  39. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  40. data/spec/faraday/rack_builder_spec.rb +26 -54
  41. data/spec/faraday/request/authorization_spec.rb +54 -24
  42. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  43. data/spec/faraday/request/json_spec.rb +111 -0
  44. data/spec/faraday/request/url_encoded_spec.rb +12 -2
  45. data/spec/faraday/request_spec.rb +5 -15
  46. data/spec/faraday/response/json_spec.rb +117 -0
  47. data/spec/faraday/response/logger_spec.rb +28 -0
  48. data/spec/faraday/response/raise_error_spec.rb +7 -4
  49. data/spec/faraday/response_spec.rb +3 -1
  50. data/spec/faraday/utils/headers_spec.rb +22 -4
  51. data/spec/faraday/utils_spec.rb +63 -1
  52. data/spec/support/fake_safe_buffer.rb +1 -1
  53. data/spec/support/helper_methods.rb +0 -37
  54. data/spec/support/shared_examples/adapter.rb +2 -2
  55. data/spec/support/shared_examples/request_method.rb +22 -21
  56. metadata +14 -80
  57. data/lib/faraday/adapter/em_http.rb +0 -289
  58. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  59. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  60. data/lib/faraday/adapter/em_synchrony.rb +0 -153
  61. data/lib/faraday/adapter/httpclient.rb +0 -152
  62. data/lib/faraday/adapter/patron.rb +0 -132
  63. data/lib/faraday/adapter/rack.rb +0 -75
  64. data/lib/faraday/adapter/typhoeus.rb +0 -15
  65. data/lib/faraday/autoload.rb +0 -92
  66. data/lib/faraday/dependency_loader.rb +0 -37
  67. data/lib/faraday/file_part.rb +0 -128
  68. data/lib/faraday/param_part.rb +0 -53
  69. data/lib/faraday/request/basic_authentication.rb +0 -20
  70. data/lib/faraday/request/multipart.rb +0 -106
  71. data/lib/faraday/request/retry.rb +0 -239
  72. data/lib/faraday/request/token_authentication.rb +0 -20
  73. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  74. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  75. data/spec/faraday/adapter/excon_spec.rb +0 -49
  76. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  77. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  78. data/spec/faraday/adapter/patron_spec.rb +0 -18
  79. data/spec/faraday/adapter/rack_spec.rb +0 -8
  80. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  81. data/spec/faraday/composite_read_io_spec.rb +0 -80
  82. data/spec/faraday/request/multipart_spec.rb +0 -302
  83. data/spec/faraday/request/retry_spec.rb +0 -242
  84. data/spec/faraday/response/middleware_spec.rb +0 -68
  85. data/spec/support/webmock_rack_app.rb +0 -68
@@ -6,15 +6,16 @@ module Faraday
6
6
  #
7
7
  # @example
8
8
  #
9
- # conn = Faraday::Connection.new 'http://sushi.com'
9
+ # conn = Faraday::Connection.new 'http://httpbingo.org'
10
10
  #
11
- # # GET http://sushi.com/nigiri
11
+ # # GET http://httpbingo.org/nigiri
12
12
  # conn.get 'nigiri'
13
13
  # # => #<Faraday::Response>
14
14
  #
15
15
  class Connection
16
16
  # A Set of allowed HTTP verbs.
17
17
  METHODS = Set.new %i[get post put delete head patch options trace]
18
+ USER_AGENT = "Faraday v#{VERSION}"
18
19
 
19
20
  # @return [Hash] URI query unencoded key/value pairs.
20
21
  attr_reader :params
@@ -26,7 +27,7 @@ module Faraday
26
27
  # Connection. This includes a default host name, scheme, port, and path.
27
28
  attr_reader :url_prefix
28
29
 
29
- # @return [Faraday::Builder] Builder for this Connection.
30
+ # @return [Faraday::RackBuilder] Builder for this Connection.
30
31
  attr_reader :builder
31
32
 
32
33
  # @return [Hash] SSL options.
@@ -63,7 +64,7 @@ module Faraday
63
64
  options = ConnectionOptions.from(options)
64
65
 
65
66
  if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
66
- options = options.merge(url)
67
+ options = Utils.deep_merge(options, url)
67
68
  url = options.url
68
69
  end
69
70
 
@@ -73,6 +74,7 @@ module Faraday
73
74
  @options = options.request
74
75
  @ssl = options.ssl
75
76
  @default_parallel_manager = options.parallel_manager
77
+ @manual_proxy = nil
76
78
 
77
79
  @builder = options.builder || begin
78
80
  # pass an empty block to Builder so it doesn't assume default middleware
@@ -88,7 +90,7 @@ module Faraday
88
90
 
89
91
  yield(self) if block_given?
90
92
 
91
- @headers[:user_agent] ||= "Faraday v#{VERSION}"
93
+ @headers[:user_agent] ||= USER_AGENT
92
94
  end
93
95
 
94
96
  def initialize_proxy(url, options)
@@ -115,7 +117,7 @@ module Faraday
115
117
 
116
118
  extend Forwardable
117
119
 
118
- def_delegators :builder, :build, :use, :request, :response, :adapter, :app
120
+ def_delegators :builder, :use, :request, :response, :adapter, :app
119
121
 
120
122
  # Closes the underlying resources and/or connections. In the case of
121
123
  # persistent connections, this closes all currently open connections
@@ -128,10 +130,10 @@ module Faraday
128
130
  # Makes a GET HTTP request without a body.
129
131
  # @!scope class
130
132
  #
131
- # @param url [String] The optional String base URL to use as a prefix for
133
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
132
134
  # all requests. Can also be the options Hash.
133
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
134
- # @param headers [Hash] unencoded HTTP header key/value pairs.
135
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
136
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
135
137
  #
136
138
  # @example
137
139
  # conn.get '/items', { page: 1 }, :accept => 'application/json'
@@ -150,10 +152,10 @@ module Faraday
150
152
  # Makes a HEAD HTTP request without a body.
151
153
  # @!scope class
152
154
  #
153
- # @param url [String] The optional String base URL to use as a prefix for
155
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
154
156
  # all requests. Can also be the options Hash.
155
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
156
- # @param headers [Hash] unencoded HTTP header key/value pairs.
157
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
158
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
157
159
  #
158
160
  # @example
159
161
  # conn.head '/items/1'
@@ -165,10 +167,10 @@ module Faraday
165
167
  # Makes a DELETE HTTP request without a body.
166
168
  # @!scope class
167
169
  #
168
- # @param url [String] The optional String base URL to use as a prefix for
170
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
169
171
  # all requests. Can also be the options Hash.
170
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
171
- # @param headers [Hash] unencoded HTTP header key/value pairs.
172
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
173
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
172
174
  #
173
175
  # @example
174
176
  # conn.delete '/items/1'
@@ -180,10 +182,10 @@ module Faraday
180
182
  # Makes a TRACE HTTP request without a body.
181
183
  # @!scope class
182
184
  #
183
- # @param url [String] The optional String base URL to use as a prefix for
185
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
184
186
  # all requests. Can also be the options Hash.
185
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
186
- # @param headers [Hash] unencoded HTTP header key/value pairs.
187
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
188
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
187
189
  #
188
190
  # @example
189
191
  # conn.connect '/items/1'
@@ -208,9 +210,9 @@ module Faraday
208
210
  #
209
211
  # @overload options(url, params = nil, headers = nil)
210
212
  # Makes an OPTIONS HTTP request to the given URL.
211
- # @param url [String] String base URL to sue as a prefix for all requests.
212
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
213
- # @param headers [Hash] unencoded HTTP header key/value pairs.
213
+ # @param url [String, URI, nil] String base URL to sue as a prefix for all requests.
214
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
215
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
214
216
  #
215
217
  # @example
216
218
  # conn.options '/items/1'
@@ -218,7 +220,7 @@ module Faraday
218
220
  # @yield [Faraday::Request] for further request customizations
219
221
  # @return [Faraday::Response]
220
222
  def options(*args)
221
- return @options if args.size.zero?
223
+ return @options if args.empty?
222
224
 
223
225
  url, params, headers = *args
224
226
  run_request(:options, url, nil, headers) do |request|
@@ -231,10 +233,10 @@ module Faraday
231
233
  # Makes a POST HTTP request with a body.
232
234
  # @!scope class
233
235
  #
234
- # @param url [String] The optional String base URL to use as a prefix for
236
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
235
237
  # all requests. Can also be the options Hash.
236
- # @param body [String] body for the request.
237
- # @param headers [Hash] unencoded HTTP header key/value pairs.
238
+ # @param body [String, nil] body for the request.
239
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
238
240
  #
239
241
  # @example
240
242
  # conn.post '/items', data, content_type: 'application/json'
@@ -253,20 +255,19 @@ module Faraday
253
255
  # Makes a PUT HTTP request with a body.
254
256
  # @!scope class
255
257
  #
256
- # @param url [String] The optional String base URL to use as a prefix for
258
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
257
259
  # all requests. Can also be the options Hash.
258
- # @param body [String] body for the request.
259
- # @param headers [Hash] unencoded HTTP header key/value pairs.
260
+ # @param body [String, nil] body for the request.
261
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
260
262
  #
261
263
  # @example
262
- # # TODO: Make it a PUT example
263
- # conn.post '/items', data, content_type: 'application/json'
264
+ # conn.put '/products/123', data, content_type: 'application/json'
264
265
  #
265
- # # Simple ElasticSearch indexing sample.
266
- # conn.post '/twitter/tweet' do |req|
267
- # req.headers[:content_type] = 'application/json'
268
- # req.params[:routing] = 'kimchy'
269
- # req.body = JSON.generate(user: 'kimchy', ...)
266
+ # # Star a gist.
267
+ # conn.put 'https://api.github.com/gists/GIST_ID/star' do |req|
268
+ # req.headers['Accept'] = 'application/vnd.github+json'
269
+ # req.headers['Authorization'] = 'Bearer <YOUR-TOKEN>'
270
+ # req.headers['X-GitHub-Api-Version'] = '2022-11-28'
270
271
  # end
271
272
  #
272
273
  # @yield [Faraday::Request] for further request customizations
@@ -281,62 +282,6 @@ module Faraday
281
282
  RUBY
282
283
  end
283
284
 
284
- # Sets up the Authorization header with these credentials, encoded
285
- # with base64.
286
- #
287
- # @param login [String] The authentication login.
288
- # @param pass [String] The authentication password.
289
- #
290
- # @example
291
- #
292
- # conn.basic_auth 'Aladdin', 'open sesame'
293
- # conn.headers['Authorization']
294
- # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
295
- #
296
- # @return [void]
297
- def basic_auth(login, pass)
298
- set_authorization_header(:basic_auth, login, pass)
299
- end
300
-
301
- # Sets up the Authorization header with the given token.
302
- #
303
- # @param token [String]
304
- # @param options [Hash] extra token options.
305
- #
306
- # @example
307
- #
308
- # conn.token_auth 'abcdef', foo: 'bar'
309
- # conn.headers['Authorization']
310
- # # => "Token token=\"abcdef\",
311
- # foo=\"bar\""
312
- #
313
- # @return [void]
314
- def token_auth(token, options = nil)
315
- set_authorization_header(:token_auth, token, options)
316
- end
317
-
318
- # Sets up a custom Authorization header.
319
- #
320
- # @param type [String] authorization type
321
- # @param token [String, Hash] token. A String value is taken literally, and
322
- # a Hash is encoded into comma-separated key/value pairs.
323
- #
324
- # @example
325
- #
326
- # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
327
- # conn.headers['Authorization']
328
- # # => "Bearer mF_9.B5f-4.1JqM"
329
- #
330
- # conn.authorization :Token, token: 'abcdef', foo: 'bar'
331
- # conn.headers['Authorization']
332
- # # => "Token token=\"abcdef\",
333
- # foo=\"bar\""
334
- #
335
- # @return [void]
336
- def authorization(type, token)
337
- set_authorization_header(:authorization, type, token)
338
- end
339
-
340
285
  # Check if the adapter is parallel-capable.
341
286
  #
342
287
  # @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
@@ -403,11 +348,11 @@ module Faraday
403
348
  # @example
404
349
  #
405
350
  # conn = Faraday::Connection.new { ... }
406
- # conn.url_prefix = "https://sushi.com/api"
351
+ # conn.url_prefix = "https://httpbingo.org/api"
407
352
  # conn.scheme # => https
408
353
  # conn.path_prefix # => "/api"
409
354
  #
410
- # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
355
+ # conn.get("nigiri?page=2") # accesses https://httpbingo.org/api/nigiri
411
356
  def url_prefix=(url, encoder = nil)
412
357
  uri = @url_prefix = Utils.URI(url)
413
358
  self.path_prefix = uri.path
@@ -416,9 +361,16 @@ module Faraday
416
361
  uri.query = nil
417
362
 
418
363
  with_uri_credentials(uri) do |user, password|
419
- basic_auth user, password
364
+ set_basic_auth(user, password)
420
365
  uri.user = uri.password = nil
421
366
  end
367
+
368
+ @proxy = proxy_from_env(url) unless @manual_proxy
369
+ end
370
+
371
+ def set_basic_auth(user, password)
372
+ header = Faraday::Utils.basic_header_from(user, password)
373
+ headers[Faraday::Request::Authorization::KEY] = header
422
374
  end
423
375
 
424
376
  # Sets the path prefix and ensures that it always has a leading
@@ -437,20 +389,20 @@ module Faraday
437
389
  # Takes a relative url for a request and combines it with the defaults
438
390
  # set on the connection instance.
439
391
  #
440
- # @param url [String]
392
+ # @param url [String, URI, nil]
441
393
  # @param extra_params [Hash]
442
394
  #
443
395
  # @example
444
396
  # conn = Faraday::Connection.new { ... }
445
- # conn.url_prefix = "https://sushi.com/api?token=abc"
397
+ # conn.url_prefix = "https://httpbingo.org/api?token=abc"
446
398
  # conn.scheme # => https
447
399
  # conn.path_prefix # => "/api"
448
400
  #
449
401
  # conn.build_url("nigiri?page=2")
450
- # # => https://sushi.com/api/nigiri?token=abc&page=2
402
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
451
403
  #
452
404
  # conn.build_url("nigiri", page: 2)
453
- # # => https://sushi.com/api/nigiri?token=abc&page=2
405
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
454
406
  #
455
407
  def build_url(url = nil, extra_params = nil)
456
408
  uri = build_exclusive_url(url)
@@ -470,10 +422,10 @@ module Faraday
470
422
  # Builds and runs the Faraday::Request.
471
423
  #
472
424
  # @param method [Symbol] HTTP method.
473
- # @param url [String, URI] String or URI to access.
474
- # @param body [Object] The request body that will eventually be converted to
425
+ # @param url [String, URI, nil] String or URI to access.
426
+ # @param body [String, nil] The request body that will eventually be converted to
475
427
  # a string.
476
- # @param headers [Hash] unencoded HTTP header key/value pairs.
428
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
477
429
  #
478
430
  # @return [Faraday::Response]
479
431
  def run_request(method, url, body, headers)
@@ -509,7 +461,7 @@ module Faraday
509
461
 
510
462
  # Build an absolute URL based on url_prefix.
511
463
  #
512
- # @param url [String, URI]
464
+ # @param url [String, URI, nil]
513
465
  # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
514
466
  # replace the query values
515
467
  # of the resulting url (default: nil).
@@ -517,19 +469,16 @@ module Faraday
517
469
  # @return [URI]
518
470
  def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
519
471
  url = nil if url.respond_to?(:empty?) && url.empty?
520
- base = url_prefix
521
- if url && base.path && base.path !~ %r{/$}
522
- base = base.dup
472
+ base = url_prefix.dup
473
+ if url && !base.path.end_with?('/')
523
474
  base.path = "#{base.path}/" # ensure trailing slash
524
475
  end
525
- url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
476
+ url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque
526
477
  uri = url ? base + url : base
527
478
  if params
528
479
  uri.query = params.to_query(params_encoder || options.params_encoder)
529
480
  end
530
- # rubocop:disable Style/SafeNavigation
531
481
  uri.query = nil if uri.query && uri.query.empty?
532
- # rubocop:enable Style/SafeNavigation
533
482
  uri
534
483
  end
535
484
 
@@ -561,14 +510,6 @@ module Faraday
561
510
  yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
562
511
  end
563
512
 
564
- def set_authorization_header(header_type, *args)
565
- header = Faraday::Request
566
- .lookup_middleware(header_type)
567
- .header(*args)
568
-
569
- headers[Faraday::Request::Authorization::KEY] = header
570
- end
571
-
572
513
  def proxy_from_env(url)
573
514
  return if Faraday.ignore_env_proxy
574
515
 
@@ -577,7 +518,11 @@ module Faraday
577
518
  case url
578
519
  when String
579
520
  uri = Utils.URI(url)
580
- uri = URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
521
+ uri = if uri.host.nil?
522
+ find_default_proxy
523
+ else
524
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
525
+ end
581
526
  when URI
582
527
  uri = url.find_proxy
583
528
  when nil
@@ -591,7 +536,7 @@ module Faraday
591
536
  end
592
537
 
593
538
  def find_default_proxy
594
- uri = ENV['http_proxy']
539
+ uri = ENV.fetch('http_proxy', nil)
595
540
  return unless uri && !uri.empty?
596
541
 
597
542
  uri = "http://#{uri}" unless uri.match?(/^http/i)
@@ -609,7 +554,7 @@ module Faraday
609
554
  end
610
555
 
611
556
  def support_parallel?(adapter)
612
- adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
557
+ adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
613
558
  end
614
559
  end
615
560
  end
@@ -62,11 +62,17 @@ module Faraday
62
62
  end
63
63
 
64
64
  def encode_array(parent, value)
65
- new_parent = "#{parent}%5B%5D"
66
- return new_parent if value.empty?
65
+ return "#{parent}%5B%5D" if value.empty?
67
66
 
68
67
  buffer = +''
69
- value.each { |val| buffer << "#{encode_pair(new_parent, val)}&" }
68
+ value.each_with_index do |val, index|
69
+ new_parent = if @array_indices
70
+ "#{parent}%5B#{index}%5D"
71
+ else
72
+ "#{parent}%5B%5D"
73
+ end
74
+ buffer << "#{encode_pair(new_parent, val)}&"
75
+ end
70
76
  buffer.chop
71
77
  end
72
78
  end
@@ -102,7 +108,7 @@ module Faraday
102
108
  subkeys = key.scan(SUBKEYS_REGEX)
103
109
  subkeys.each_with_index do |subkey, i|
104
110
  is_array = subkey =~ /[\[\]]+\Z/
105
- subkey = $` if is_array
111
+ subkey = Regexp.last_match.pre_match if is_array
106
112
  last_subkey = i == subkeys.length - 1
107
113
 
108
114
  context = prepare_context(context, subkey, is_array, last_subkey)
@@ -124,7 +130,7 @@ module Faraday
124
130
  value_type = is_array ? Array : Hash
125
131
  if context[subkey] && !context[subkey].is_a?(value_type)
126
132
  raise TypeError, "expected #{value_type.name} " \
127
- "(got #{context[subkey].class.name}) for param `#{subkey}'"
133
+ "(got #{context[subkey].class.name}) for param `#{subkey}'"
128
134
  end
129
135
 
130
136
  context[subkey] ||= value_type.new
@@ -161,7 +167,7 @@ module Faraday
161
167
  # for your requests.
162
168
  module NestedParamsEncoder
163
169
  class << self
164
- attr_accessor :sort_params
170
+ attr_accessor :sort_params, :array_indices
165
171
 
166
172
  extend Forwardable
167
173
  def_delegators :'Faraday::Utils', :escape, :unescape
@@ -169,6 +175,7 @@ module Faraday
169
175
 
170
176
  # Useful default for OAuth and caching.
171
177
  @sort_params = true
178
+ @array_indices = false
172
179
 
173
180
  extend EncodeMethods
174
181
  extend DecodeMethods
data/lib/faraday/error.rb CHANGED
@@ -6,7 +6,7 @@ module Faraday
6
6
  class Error < StandardError
7
7
  attr_reader :response, :wrapped_exception
8
8
 
9
- def initialize(exc, response = nil)
9
+ def initialize(exc = nil, response = nil)
10
10
  @wrapped_exception = nil unless defined?(@wrapped_exception)
11
11
  @response = nil unless defined?(@response)
12
12
  super(exc_msg_and_response!(exc, response))
@@ -52,6 +52,7 @@ module Faraday
52
52
  # :body - Optional string HTTP response body.
53
53
  # :request - Hash
54
54
  # :method - Symbol with the request HTTP method.
55
+ # :url - URI object with the url requested.
55
56
  # :url_path - String with the url path requested.
56
57
  # :params - String key/value hash of query params
57
58
  # present in the request.
@@ -140,13 +141,7 @@ module Faraday
140
141
  class SSLError < Error
141
142
  end
142
143
 
143
- # Raised by FaradayMiddleware::ResponseMiddleware
144
+ # Raised by middlewares that parse the response, like the JSON response middleware.
144
145
  class ParsingError < Error
145
146
  end
146
-
147
- # Exception used to control the Retry middleware.
148
- #
149
- # @see Faraday::Request::Retry
150
- class RetriableResponse < Error
151
- end
152
147
  end
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp'
3
+ require 'pp' # rubocop:disable Lint/RedundantRequireStatement
4
+
4
5
  module Faraday
5
6
  module Logging
6
7
  # Serves as an integration point to customize logging
7
8
  class Formatter
8
9
  extend Forwardable
9
10
 
10
- DEFAULT_OPTIONS = { headers: true, bodies: false,
11
+ DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false,
11
12
  log_level: :info }.freeze
12
13
 
13
14
  def initialize(logger:, options:)
@@ -36,6 +37,18 @@ module Faraday
36
37
  log_body('response', env[:body]) if env[:body] && log_body?(:response)
37
38
  end
38
39
 
40
+ def exception(exc)
41
+ return unless log_errors?
42
+
43
+ error_log = proc { exc.full_message }
44
+ public_send(log_level, 'error', &error_log)
45
+
46
+ log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error)
47
+ return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error)
48
+
49
+ log_body('error', exc.response_body)
50
+ end
51
+
39
52
  def filter(filter_word, filter_replacement)
40
53
  @filter.push([filter_word, filter_replacement])
41
54
  end
@@ -76,6 +89,10 @@ module Faraday
76
89
  end
77
90
  end
78
91
 
92
+ def log_errors?
93
+ @options[:errors]
94
+ end
95
+
79
96
  def apply_filters(output)
80
97
  @filter.each do |pattern, replacement|
81
98
  output = output.to_s.gsub(pattern, replacement)
@@ -4,7 +4,6 @@ module Faraday
4
4
  # Middleware is the basic base class of any Faraday middleware.
5
5
  class Middleware
6
6
  extend MiddlewareRegistry
7
- extend DependencyLoader
8
7
 
9
8
  attr_reader :app, :options
10
9
 
@@ -18,6 +17,9 @@ module Faraday
18
17
  app.call(env).on_complete do |environment|
19
18
  on_complete(environment) if respond_to?(:on_complete)
20
19
  end
20
+ rescue StandardError => e
21
+ on_error(e) if respond_to?(:on_error)
22
+ raise
21
23
  end
22
24
 
23
25
  def close
@@ -6,59 +6,26 @@ module Faraday
6
6
  # Adds the ability for other modules to register and lookup
7
7
  # middleware classes.
8
8
  module MiddlewareRegistry
9
+ def registered_middleware
10
+ @registered_middleware ||= {}
11
+ end
12
+
9
13
  # Register middleware class(es) on the current module.
10
14
  #
11
- # @param autoload_path [String] Middleware autoload path
12
- # @param mapping [Hash{
13
- # Symbol => Module,
14
- # Symbol => Array<Module, Symbol, String>,
15
- # }] Middleware mapping from a lookup symbol to a reference to the
16
- # middleware.
17
- # Classes can be expressed as:
18
- # - a fully qualified constant
19
- # - a Symbol
20
- # - a Proc that will be lazily called to return the former
21
- # - an array is given, its first element is the constant or symbol,
22
- # and its second is a file to `require`.
15
+ # @param mappings [Hash] Middleware mappings from a lookup symbol to a middleware class.
23
16
  # @return [void]
24
17
  #
25
18
  # @example Lookup by a constant
26
19
  #
27
20
  # module Faraday
28
- # class Whatever
21
+ # class Whatever < Middleware
29
22
  # # Middleware looked up by :foo returns Faraday::Whatever::Foo.
30
- # register_middleware foo: Foo
31
- # end
32
- # end
33
- #
34
- # @example Lookup by a symbol
35
- #
36
- # module Faraday
37
- # class Whatever
38
- # # Middleware looked up by :bar returns
39
- # # Faraday::Whatever.const_get(:Bar)
40
- # register_middleware bar: :Bar
41
- # end
42
- # end
43
- #
44
- # @example Lookup by a symbol and string in an array
45
- #
46
- # module Faraday
47
- # class Whatever
48
- # # Middleware looked up by :baz requires 'baz' and returns
49
- # # Faraday::Whatever.const_get(:Baz)
50
- # register_middleware baz: [:Baz, 'baz']
23
+ # register_middleware(foo: Whatever)
51
24
  # end
52
25
  # end
53
- #
54
- def register_middleware(autoload_path = nil, mapping = nil)
55
- if mapping.nil?
56
- mapping = autoload_path
57
- autoload_path = nil
58
- end
26
+ def register_middleware(**mappings)
59
27
  middleware_mutex do
60
- @middleware_autoload_path = autoload_path if autoload_path
61
- (@registered_middleware ||= {}).update(mapping)
28
+ registered_middleware.update(mappings)
62
29
  end
63
30
  end
64
31
 
@@ -66,7 +33,7 @@ module Faraday
66
33
  #
67
34
  # @param key [Symbol] key for the registered middleware.
68
35
  def unregister_middleware(key)
69
- @registered_middleware.delete(key)
36
+ registered_middleware.delete(key)
70
37
  end
71
38
 
72
39
  # Lookup middleware class with a registered Symbol shortcut.
@@ -78,30 +45,27 @@ module Faraday
78
45
  # @example
79
46
  #
80
47
  # module Faraday
81
- # class Whatever
82
- # register_middleware foo: Foo
48
+ # class Whatever < Middleware
49
+ # register_middleware(foo: Whatever)
83
50
  # end
84
51
  # end
85
52
  #
86
- # Faraday::Whatever.lookup_middleware(:foo)
87
- # # => Faraday::Whatever::Foo
88
- #
53
+ # Faraday::Middleware.lookup_middleware(:foo)
54
+ # # => Faraday::Whatever
89
55
  def lookup_middleware(key)
90
56
  load_middleware(key) ||
91
57
  raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
92
58
  end
93
59
 
60
+ private
61
+
94
62
  def middleware_mutex(&block)
95
63
  @middleware_mutex ||= Monitor.new
96
64
  @middleware_mutex.synchronize(&block)
97
65
  end
98
66
 
99
- def fetch_middleware(key)
100
- defined?(@registered_middleware) && @registered_middleware[key]
101
- end
102
-
103
67
  def load_middleware(key)
104
- value = fetch_middleware(key)
68
+ value = registered_middleware[key]
105
69
  case value
106
70
  when Module
107
71
  value
@@ -113,16 +77,6 @@ module Faraday
113
77
  middleware_mutex do
114
78
  @registered_middleware[key] = value.call
115
79
  end
116
- when Array
117
- middleware_mutex do
118
- const, path = value
119
- if (root = @middleware_autoload_path)
120
- path = "#{root}/#{path}"
121
- end
122
- require(path)
123
- @registered_middleware[key] = const
124
- end
125
- load_middleware(key)
126
80
  end
127
81
  end
128
82
  end