faraday 2.5.2 → 2.9.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 +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 }