faraday 2.5.2 → 2.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +29 -17
  4. data/Rakefile +6 -1
  5. data/lib/faraday/adapter/test.rb +20 -7
  6. data/lib/faraday/adapter.rb +2 -3
  7. data/lib/faraday/connection.rb +49 -54
  8. data/lib/faraday/encoders/nested_params_encoder.rb +1 -1
  9. data/lib/faraday/error.rb +17 -3
  10. data/lib/faraday/logging/formatter.rb +27 -15
  11. data/lib/faraday/middleware.rb +3 -0
  12. data/lib/faraday/options/connection_options.rb +7 -6
  13. data/lib/faraday/options/env.rb +68 -63
  14. data/lib/faraday/options/proxy_options.rb +7 -3
  15. data/lib/faraday/options/request_options.rb +7 -6
  16. data/lib/faraday/options/ssl_options.rb +51 -50
  17. data/lib/faraday/options.rb +4 -3
  18. data/lib/faraday/rack_builder.rb +0 -1
  19. data/lib/faraday/request/authorization.rb +8 -3
  20. data/lib/faraday/request/instrumentation.rb +3 -1
  21. data/lib/faraday/request/json.rb +18 -3
  22. data/lib/faraday/request.rb +11 -8
  23. data/lib/faraday/response/json.rb +21 -1
  24. data/lib/faraday/response/logger.rb +4 -0
  25. data/lib/faraday/response/raise_error.rb +24 -5
  26. data/lib/faraday/response.rb +2 -1
  27. data/lib/faraday/utils/headers.rb +14 -3
  28. data/lib/faraday/utils.rb +3 -4
  29. data/lib/faraday/version.rb +1 -1
  30. data/spec/faraday/adapter/test_spec.rb +29 -0
  31. data/spec/faraday/connection_spec.rb +17 -2
  32. data/spec/faraday/error_spec.rb +31 -6
  33. data/spec/faraday/middleware_spec.rb +18 -0
  34. data/spec/faraday/options/options_spec.rb +1 -1
  35. data/spec/faraday/options/proxy_options_spec.rb +8 -0
  36. data/spec/faraday/params_encoders/nested_spec.rb +2 -1
  37. data/spec/faraday/request/authorization_spec.rb +35 -0
  38. data/spec/faraday/request/json_spec.rb +88 -0
  39. data/spec/faraday/response/json_spec.rb +89 -0
  40. data/spec/faraday/response/logger_spec.rb +38 -0
  41. data/spec/faraday/response/raise_error_spec.rb +40 -1
  42. data/spec/faraday/response_spec.rb +3 -1
  43. data/spec/faraday/utils/headers_spec.rb +29 -2
  44. data/spec/faraday_spec.rb +10 -4
  45. data/spec/spec_helper.rb +6 -5
  46. metadata +7 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5bf37c33313ee7027a44ba34906e46285c4bf4c51205f58e3ad50c0d5b7a3ab
4
- data.tar.gz: 1bc57e0e2909550e60575320fbaa4bb75d17e914462ed57d06fe2cccd81804fe
3
+ metadata.gz: d2795a487e8f0330545b6b9720029b597b0f0f36d33ed47bf3a7ab5ec8e2d583
4
+ data.tar.gz: a892c9ceebf1a9b5499ca7c6f20a1f6bb3c8a632bcf953f83af0ac17814c0691
5
5
  SHA512:
6
- metadata.gz: ed0374b593a768aad905cf1c175cc86fc0892757a3b549def26e09a84016ffd6674d8e920e6c14b7709bf505a3b0a682b0191b2239b4eefe1f09ce23fad999b2
7
- data.tar.gz: 59ce275bfb56375648ee5966e0fd2b7326117bd2d62789533d4856021a2c6a96f859f813dc4c9b472cd0c7579fa38765ba027193b69352a6e4740e21fd0bc3b8
6
+ metadata.gz: dc55e018b7b5cec1d5538194841c74a643182d0bb6bc3a73bf5ca1c3c7c88f84998f8b4f90165bffe22b01422e3d90c7bbf6c035714c563bb09265bd34029169
7
+ data.tar.gz: 05c24fe02e969616d069ba3b02fa7fddfb5c70cb504bfd39ca60983d12aaa47207f985c1e5a1a24d29c71c6cecbe899eb2252f4a8f9458d8681e06584d7016fc
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2022 Rick Olson, Zack Hobson
1
+ Copyright (c) 2009-2023 Rick Olson, Zack Hobson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,26 +1,41 @@
1
- # [![Faraday](./docs/assets/img/repo-card-slim.png)][website]
1
+ # [![Faraday](./docs/_media/home-logo.svg)][website]
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
4
4
  [![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
5
5
  [![GitHub Discussions](https://img.shields.io/github/discussions/lostisland/faraday?logo=github)](https://github.com/lostisland/faraday/discussions)
6
6
 
7
-
8
7
  Faraday is an HTTP client library abstraction layer that provides a common interface over many
9
8
  adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
10
- You probably don't want to use Faraday directly in your project, as it will lack an actual client library to perform
11
- requests. Instead, you probably want to have a look at [Awesome Faraday][awesome] for a list of available adapters.
9
+ Take a look at [Awesome Faraday][awesome] for a list of available adapters and middleware.
10
+
11
+ ## Why use Faraday?
12
+
13
+ Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses,
14
+ making it easier to build sophisticated API clients or web service libraries that abstract away
15
+ the details of how HTTP requests are made.
16
+
17
+ Faraday comes with a lot of features out of the box, such as:
18
+ * Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
19
+ * Persistent connections (keep-alive)
20
+ * Parallel requests
21
+ * Automatic response parsing (JSON, XML, YAML)
22
+ * Customization of the request/response cycle with middleware
23
+ * Support for streaming responses
24
+ * Support for uploading files
25
+ * And much more!
12
26
 
13
27
  ## Getting Started
14
28
 
15
29
  The best starting point is the [Faraday Website][website], with its introduction and explanation.
16
- Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally.
30
+
31
+ Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally, or take a look at [Advanced techniques for calling HTTP APIs in Ruby](https://mattbrictson.com/blog/advanced-http-techniques-in-ruby) blog post from [@mattbrictson](https://github.com/mattbrictson) 🚀
17
32
 
18
33
  ## Supported Ruby versions
19
34
 
20
35
  This library aims to support and is [tested against][actions] the currently officially supported Ruby
21
36
  implementations. This means that, even without a major release, we could add or drop support for Ruby versions,
22
37
  following their [EOL](https://endoflife.date/ruby).
23
- Currently that means we support Ruby 2.6+
38
+ Currently that means we support Ruby 3.0+
24
39
 
25
40
  If something doesn't work on one of these Ruby versions, it's a bug.
26
41
 
@@ -42,14 +57,11 @@ Open the issues page and check for the `help wanted` label!
42
57
  But before you start coding, please read our [Contributing Guide][contributing]
43
58
 
44
59
  ## Copyright
45
- © 2009 - 2022, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
46
-
47
- [awesome]: https://github.com/lostisland/awesome-faraday/#adapters
48
- [website]: https://lostisland.github.io/faraday
49
- [faraday_team]: https://lostisland.github.io/faraday/team
50
- [contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
51
- [apidoc]: https://www.rubydoc.info/github/lostisland/faraday
52
- [actions]: https://github.com/lostisland/faraday/actions
53
- [jruby]: http://jruby.org/
54
- [rubinius]: http://rubini.us/
55
- [license]: LICENSE.md
60
+
61
+ © 2009 - 2023, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
62
+
63
+ [awesome]: https://github.com/lostisland/awesome-faraday/#adapters
64
+ [website]: https://lostisland.github.io/faraday
65
+ [contributing]: https://github.com/lostisland/faraday/blob/main/.github/CONTRIBUTING.md
66
+ [apidoc]: https://www.rubydoc.info/github/lostisland/faraday
67
+ [actions]: https://github.com/lostisland/faraday/actions
data/Rakefile CHANGED
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rspec/core/rake_task'
4
+ require 'bundler'
4
5
 
5
- RSpec::Core::RakeTask.new(:spec)
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |task|
9
+ task.ruby_opts = %w[-W]
10
+ end
6
11
 
7
12
  task default: :spec
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'timeout'
4
+
3
5
  module Faraday
4
6
  class Adapter
5
7
  # @example
@@ -144,7 +146,7 @@ module Faraday
144
146
  # which means that all of a path, parameters, and headers must be the same as an actual request.
145
147
  def strict_mode=(value)
146
148
  @strict_mode = value
147
- @stack.each do |_method, stubs|
149
+ @stack.each_value do |stubs|
148
150
  stubs.each do |stub|
149
151
  stub.strict_mode = value
150
152
  end
@@ -182,7 +184,7 @@ module Faraday
182
184
  end
183
185
 
184
186
  # Stub request
185
- class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
187
+ Stub = Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) do
186
188
  # @param env [Faraday::Env]
187
189
  def matches?(env)
188
190
  request_host = env[:url].host
@@ -238,7 +240,7 @@ module Faraday
238
240
  end
239
241
 
240
242
  def body_match?(request_body)
241
- return true if body.to_s.size.zero?
243
+ return true if body.to_s.empty?
242
244
 
243
245
  case body
244
246
  when Proc
@@ -273,15 +275,26 @@ module Faraday
273
275
 
274
276
  unless stub
275
277
  raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
276
- "#{env[:url]} #{env[:body]}"
278
+ "#{env[:url]} #{env[:body]} #{env[:headers]}"
277
279
  end
278
280
 
279
281
  block_arity = stub.block.arity
282
+ params = if block_arity >= 0
283
+ [env, meta].take(block_arity)
284
+ else
285
+ [env, meta]
286
+ end
287
+
288
+ timeout = request_timeout(:open, env[:request])
289
+ timeout ||= request_timeout(:read, env[:request])
290
+
280
291
  status, headers, body =
281
- if block_arity >= 0
282
- stub.block.call(*[env, meta].take(block_arity))
292
+ if timeout
293
+ ::Timeout.timeout(timeout, Faraday::TimeoutError) do
294
+ stub.block.call(*params)
295
+ end
283
296
  else
284
- stub.block.call(env, meta)
297
+ stub.block.call(*params)
285
298
  end
286
299
 
287
300
  # We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
@@ -26,7 +26,7 @@ module Faraday
26
26
  self.supports_parallel = false
27
27
 
28
28
  def initialize(_app = nil, opts = {}, &block)
29
- @app = ->(env) { env.response }
29
+ @app = lambda(&:response)
30
30
  @connection_options = opts
31
31
  @config_block = block
32
32
  end
@@ -78,8 +78,7 @@ module Faraday
78
78
  # @param type [Symbol] Describes which timeout setting to get: :read,
79
79
  # :write, or :open.
80
80
  # @param options [Hash] Hash containing Symbol keys like :timeout,
81
- # :read_timeout, :write_timeout, :open_timeout, or
82
- # :timeout
81
+ # :read_timeout, :write_timeout, or :open_timeout
83
82
  #
84
83
  # @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
85
84
  # has been set.
@@ -15,7 +15,7 @@ module Faraday
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
+ USER_AGENT = "Faraday v#{VERSION}".freeze
19
19
 
20
20
  # @return [Hash] URI query unencoded key/value pairs.
21
21
  attr_reader :params
@@ -130,10 +130,10 @@ module Faraday
130
130
  # Makes a GET HTTP request without a body.
131
131
  # @!scope class
132
132
  #
133
- # @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
134
134
  # all requests. Can also be the options Hash.
135
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
136
- # @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.
137
137
  #
138
138
  # @example
139
139
  # conn.get '/items', { page: 1 }, :accept => 'application/json'
@@ -152,10 +152,10 @@ module Faraday
152
152
  # Makes a HEAD HTTP request without a body.
153
153
  # @!scope class
154
154
  #
155
- # @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
156
156
  # all requests. Can also be the options Hash.
157
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
158
- # @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.
159
159
  #
160
160
  # @example
161
161
  # conn.head '/items/1'
@@ -167,10 +167,10 @@ module Faraday
167
167
  # Makes a DELETE HTTP request without a body.
168
168
  # @!scope class
169
169
  #
170
- # @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
171
171
  # all requests. Can also be the options Hash.
172
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
173
- # @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.
174
174
  #
175
175
  # @example
176
176
  # conn.delete '/items/1'
@@ -182,10 +182,10 @@ module Faraday
182
182
  # Makes a TRACE HTTP request without a body.
183
183
  # @!scope class
184
184
  #
185
- # @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
186
186
  # all requests. Can also be the options Hash.
187
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
188
- # @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.
189
189
  #
190
190
  # @example
191
191
  # conn.connect '/items/1'
@@ -210,9 +210,9 @@ module Faraday
210
210
  #
211
211
  # @overload options(url, params = nil, headers = nil)
212
212
  # Makes an OPTIONS HTTP request to the given URL.
213
- # @param url [String] String base URL to sue as a prefix for all requests.
214
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
215
- # @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.
216
216
  #
217
217
  # @example
218
218
  # conn.options '/items/1'
@@ -220,7 +220,7 @@ module Faraday
220
220
  # @yield [Faraday::Request] for further request customizations
221
221
  # @return [Faraday::Response]
222
222
  def options(*args)
223
- return @options if args.size.zero?
223
+ return @options if args.empty?
224
224
 
225
225
  url, params, headers = *args
226
226
  run_request(:options, url, nil, headers) do |request|
@@ -233,10 +233,10 @@ module Faraday
233
233
  # Makes a POST HTTP request with a body.
234
234
  # @!scope class
235
235
  #
236
- # @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
237
237
  # all requests. Can also be the options Hash.
238
- # @param body [String] body for the request.
239
- # @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.
240
240
  #
241
241
  # @example
242
242
  # conn.post '/items', data, content_type: 'application/json'
@@ -255,20 +255,19 @@ module Faraday
255
255
  # Makes a PUT HTTP request with a body.
256
256
  # @!scope class
257
257
  #
258
- # @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
259
259
  # all requests. Can also be the options Hash.
260
- # @param body [String] body for the request.
261
- # @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.
262
262
  #
263
263
  # @example
264
- # # TODO: Make it a PUT example
265
- # conn.post '/items', data, content_type: 'application/json'
264
+ # conn.put '/products/123', data, content_type: 'application/json'
266
265
  #
267
- # # Simple ElasticSearch indexing sample.
268
- # conn.post '/twitter/tweet' do |req|
269
- # req.headers[:content_type] = 'application/json'
270
- # req.params[:routing] = 'kimchy'
271
- # 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'
272
271
  # end
273
272
  #
274
273
  # @yield [Faraday::Request] for further request customizations
@@ -390,7 +389,7 @@ module Faraday
390
389
  # Takes a relative url for a request and combines it with the defaults
391
390
  # set on the connection instance.
392
391
  #
393
- # @param url [String]
392
+ # @param url [String, URI, nil]
394
393
  # @param extra_params [Hash]
395
394
  #
396
395
  # @example
@@ -423,10 +422,10 @@ module Faraday
423
422
  # Builds and runs the Faraday::Request.
424
423
  #
425
424
  # @param method [Symbol] HTTP method.
426
- # @param url [String, URI] String or URI to access.
427
- # @param body [Object] The request body that will eventually be converted to
428
- # a string.
429
- # @param headers [Hash] unencoded HTTP header key/value pairs.
425
+ # @param url [String, URI, nil] String or URI to access.
426
+ # @param body [String, Hash, Array, nil] The request body that will eventually be converted to
427
+ # a string; middlewares can be used to support more complex types.
428
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
430
429
  #
431
430
  # @return [Faraday::Response]
432
431
  def run_request(method, url, body, headers)
@@ -462,7 +461,7 @@ module Faraday
462
461
 
463
462
  # Build an absolute URL based on url_prefix.
464
463
  #
465
- # @param url [String, URI]
464
+ # @param url [String, URI, nil]
466
465
  # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
467
466
  # replace the query values
468
467
  # of the resulting url (default: nil).
@@ -471,10 +470,11 @@ module Faraday
471
470
  def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
472
471
  url = nil if url.respond_to?(:empty?) && url.empty?
473
472
  base = url_prefix.dup
474
- if url && base.path && base.path !~ %r{/$}
473
+ if url && !base.path.end_with?('/')
475
474
  base.path = "#{base.path}/" # ensure trailing slash
476
475
  end
477
- url = url.to_s.gsub(':', '%3A') if url && URI.parse(url.to_s).opaque
476
+ # Ensure relative url will be parsed correctly (such as `service:search` )
477
+ url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?('http://', 'https://', '/', './', '../')
478
478
  uri = url ? base + url : base
479
479
  if params
480
480
  uri.query = params.to_query(params_encoder || options.params_encoder)
@@ -515,22 +515,17 @@ module Faraday
515
515
  return if Faraday.ignore_env_proxy
516
516
 
517
517
  uri = nil
518
- if URI.parse('').respond_to?(:find_proxy)
519
- case url
520
- when String
521
- uri = Utils.URI(url)
522
- uri = if uri.host.nil?
523
- find_default_proxy
524
- else
525
- URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
526
- end
527
- when URI
528
- uri = url.find_proxy
529
- when nil
530
- uri = find_default_proxy
531
- end
532
- else
533
- warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
518
+ case url
519
+ when String
520
+ uri = Utils.URI(url)
521
+ uri = if uri.host.nil?
522
+ find_default_proxy
523
+ else
524
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
525
+ end
526
+ when URI
527
+ uri = url.find_proxy
528
+ when nil
534
529
  uri = find_default_proxy
535
530
  end
536
531
  ProxyOptions.from(uri) if uri
@@ -102,7 +102,7 @@ module Faraday
102
102
 
103
103
  protected
104
104
 
105
- SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
105
+ SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/
106
106
 
107
107
  def decode_pair(key, value, context)
108
108
  subkeys = key.scan(SUBKEYS_REGEX)
data/lib/faraday/error.rb CHANGED
@@ -29,15 +29,21 @@ module Faraday
29
29
  end
30
30
 
31
31
  def response_status
32
- @response[:status] if @response
32
+ return unless @response
33
+
34
+ @response.is_a?(Faraday::Response) ? @response.status : @response[:status]
33
35
  end
34
36
 
35
37
  def response_headers
36
- @response[:headers] if @response
38
+ return unless @response
39
+
40
+ @response.is_a?(Faraday::Response) ? @response.headers : @response[:headers]
37
41
  end
38
42
 
39
43
  def response_body
40
- @response[:body] if @response
44
+ return unless @response
45
+
46
+ @response.is_a?(Faraday::Response) ? @response.body : @response[:body]
41
47
  end
42
48
 
43
49
  protected
@@ -106,6 +112,10 @@ module Faraday
106
112
  class ProxyAuthError < ClientError
107
113
  end
108
114
 
115
+ # Raised by Faraday::Response::RaiseError in case of a 408 response.
116
+ class RequestTimeoutError < ClientError
117
+ end
118
+
109
119
  # Raised by Faraday::Response::RaiseError in case of a 409 response.
110
120
  class ConflictError < ClientError
111
121
  end
@@ -114,6 +124,10 @@ module Faraday
114
124
  class UnprocessableEntityError < ClientError
115
125
  end
116
126
 
127
+ # Raised by Faraday::Response::RaiseError in case of a 429 response.
128
+ class TooManyRequestsError < ClientError
129
+ end
130
+
117
131
  # Faraday server error class. Represents 5xx status responses.
118
132
  class ServerError < Error
119
133
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp'
3
+ require 'pp' # This require is necessary for Hash#pretty_inspect to work, do not remove it, people rely on it.
4
4
 
5
5
  module Faraday
6
6
  module Logging
@@ -8,35 +8,47 @@ module Faraday
8
8
  class Formatter
9
9
  extend Forwardable
10
10
 
11
- DEFAULT_OPTIONS = { headers: true, bodies: false,
11
+ DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false,
12
12
  log_level: :info }.freeze
13
13
 
14
14
  def initialize(logger:, options:)
15
15
  @logger = logger
16
- @filter = []
17
16
  @options = DEFAULT_OPTIONS.merge(options)
17
+ unless %i[debug info warn error fatal].include?(@options[:log_level])
18
+ @options[:log_level] = :info
19
+ end
20
+ @filter = []
18
21
  end
19
22
 
20
23
  def_delegators :@logger, :debug, :info, :warn, :error, :fatal
21
24
 
22
25
  def request(env)
23
- request_log = proc do
26
+ public_send(log_level, 'request') do
24
27
  "#{env.method.upcase} #{apply_filters(env.url.to_s)}"
25
28
  end
26
- public_send(log_level, 'request', &request_log)
27
29
 
28
30
  log_headers('request', env.request_headers) if log_headers?(:request)
29
31
  log_body('request', env[:body]) if env[:body] && log_body?(:request)
30
32
  end
31
33
 
32
34
  def response(env)
33
- status = proc { "Status #{env.status}" }
34
- public_send(log_level, 'response', &status)
35
+ public_send(log_level, 'response') { "Status #{env.status}" }
35
36
 
36
37
  log_headers('response', env.response_headers) if log_headers?(:response)
37
38
  log_body('response', env[:body]) if env[:body] && log_body?(:response)
38
39
  end
39
40
 
41
+ def exception(exc)
42
+ return unless log_errors?
43
+
44
+ public_send(log_level, 'error') { exc.full_message }
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
+
40
52
  def filter(filter_word, filter_replacement)
41
53
  @filter.push([filter_word, filter_replacement])
42
54
  end
@@ -44,6 +56,8 @@ module Faraday
44
56
  private
45
57
 
46
58
  def dump_headers(headers)
59
+ return if headers.nil?
60
+
47
61
  headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
48
62
  end
49
63
 
@@ -77,6 +91,10 @@ module Faraday
77
91
  end
78
92
  end
79
93
 
94
+ def log_errors?
95
+ @options[:errors]
96
+ end
97
+
80
98
  def apply_filters(output)
81
99
  @filter.each do |pattern, replacement|
82
100
  output = output.to_s.gsub(pattern, replacement)
@@ -85,21 +103,15 @@ module Faraday
85
103
  end
86
104
 
87
105
  def log_level
88
- unless %i[debug info warn error fatal].include?(@options[:log_level])
89
- return :info
90
- end
91
-
92
106
  @options[:log_level]
93
107
  end
94
108
 
95
109
  def log_headers(type, headers)
96
- headers_log = proc { apply_filters(dump_headers(headers)) }
97
- public_send(log_level, type, &headers_log)
110
+ public_send(log_level, type) { apply_filters(dump_headers(headers)) }
98
111
  end
99
112
 
100
113
  def log_body(type, body)
101
- body_log = proc { apply_filters(dump_body(body)) }
102
- public_send(log_level, type, &body_log)
114
+ public_send(log_level, type) { apply_filters(dump_body(body)) }
103
115
  end
104
116
  end
105
117
  end
@@ -17,6 +17,9 @@ module Faraday
17
17
  app.call(env).on_complete do |environment|
18
18
  on_complete(environment) if respond_to?(:on_complete)
19
19
  end
20
+ rescue StandardError => e
21
+ on_error(e) if respond_to?(:on_error)
22
+ raise
20
23
  end
21
24
 
22
25
  def close
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # ConnectionOptions contains the configurable properties for a Faraday
5
- # connection object.
6
- class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
7
- :parallel_manager, :params, :headers,
8
- :builder_class)
9
-
4
+ # @!parse
5
+ # # ConnectionOptions contains the configurable properties for a Faraday
6
+ # # connection object.
7
+ # class ConnectionOptions < Options; end
8
+ ConnectionOptions = Options.new(:request, :proxy, :ssl, :builder, :url,
9
+ :parallel_manager, :params, :headers,
10
+ :builder_class) do
10
11
  options request: RequestOptions, ssl: SSLOptions
11
12
 
12
13
  memoized(:request) { self.class.options_for(:request).new }