faraday 1.0.0 → 2.9.0

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +35 -23
  5. data/Rakefile +3 -1
  6. data/examples/client_spec.rb +68 -14
  7. data/examples/client_test.rb +80 -15
  8. data/lib/faraday/adapter/test.rb +117 -52
  9. data/lib/faraday/adapter.rb +6 -20
  10. data/lib/faraday/adapter_registry.rb +3 -1
  11. data/lib/faraday/connection.rb +73 -132
  12. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  13. data/lib/faraday/encoders/nested_params_encoder.rb +20 -8
  14. data/lib/faraday/error.rb +37 -8
  15. data/lib/faraday/logging/formatter.rb +28 -15
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +17 -5
  18. data/lib/faraday/middleware_registry.rb +17 -63
  19. data/lib/faraday/options/connection_options.rb +7 -6
  20. data/lib/faraday/options/env.rb +85 -62
  21. data/lib/faraday/options/proxy_options.rb +11 -3
  22. data/lib/faraday/options/request_options.rb +7 -6
  23. data/lib/faraday/options/ssl_options.rb +56 -45
  24. data/lib/faraday/options.rb +11 -14
  25. data/lib/faraday/rack_builder.rb +35 -32
  26. data/lib/faraday/request/authorization.rb +37 -36
  27. data/lib/faraday/request/instrumentation.rb +5 -1
  28. data/lib/faraday/request/json.rb +70 -0
  29. data/lib/faraday/request/url_encoded.rb +8 -2
  30. data/lib/faraday/request.rb +22 -29
  31. data/lib/faraday/response/json.rb +73 -0
  32. data/lib/faraday/response/logger.rb +8 -4
  33. data/lib/faraday/response/raise_error.rb +41 -3
  34. data/lib/faraday/response.rb +10 -23
  35. data/lib/faraday/utils/headers.rb +9 -4
  36. data/lib/faraday/utils.rb +22 -10
  37. data/lib/faraday/version.rb +5 -0
  38. data/lib/faraday.rb +49 -58
  39. data/spec/faraday/adapter/test_spec.rb +442 -0
  40. data/spec/faraday/connection_spec.rb +207 -90
  41. data/spec/faraday/error_spec.rb +45 -5
  42. data/spec/faraday/middleware_registry_spec.rb +31 -0
  43. data/spec/faraday/middleware_spec.rb +50 -6
  44. data/spec/faraday/options/env_spec.rb +8 -2
  45. data/spec/faraday/options/options_spec.rb +1 -1
  46. data/spec/faraday/options/proxy_options_spec.rb +15 -0
  47. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  48. data/spec/faraday/params_encoders/nested_spec.rb +16 -0
  49. data/spec/faraday/rack_builder_spec.rb +171 -50
  50. data/spec/faraday/request/authorization_spec.rb +54 -24
  51. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  52. data/spec/faraday/request/json_spec.rb +199 -0
  53. data/spec/faraday/request/url_encoded_spec.rb +25 -2
  54. data/spec/faraday/request_spec.rb +11 -10
  55. data/spec/faraday/response/json_spec.rb +189 -0
  56. data/spec/faraday/response/logger_spec.rb +38 -0
  57. data/spec/faraday/response/raise_error_spec.rb +105 -0
  58. data/spec/faraday/response_spec.rb +3 -1
  59. data/spec/faraday/utils/headers_spec.rb +22 -4
  60. data/spec/faraday/utils_spec.rb +63 -1
  61. data/spec/faraday_spec.rb +8 -4
  62. data/spec/spec_helper.rb +6 -5
  63. data/spec/support/fake_safe_buffer.rb +1 -1
  64. data/spec/support/helper_methods.rb +0 -37
  65. data/spec/support/shared_examples/adapter.rb +4 -3
  66. data/spec/support/shared_examples/request_method.rb +60 -31
  67. metadata +19 -44
  68. data/UPGRADING.md +0 -55
  69. data/lib/faraday/adapter/em_http.rb +0 -285
  70. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  71. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  72. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  73. data/lib/faraday/adapter/excon.rb +0 -124
  74. data/lib/faraday/adapter/httpclient.rb +0 -151
  75. data/lib/faraday/adapter/net_http.rb +0 -209
  76. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  77. data/lib/faraday/adapter/patron.rb +0 -132
  78. data/lib/faraday/adapter/rack.rb +0 -75
  79. data/lib/faraday/adapter/typhoeus.rb +0 -15
  80. data/lib/faraday/autoload.rb +0 -95
  81. data/lib/faraday/dependency_loader.rb +0 -37
  82. data/lib/faraday/file_part.rb +0 -128
  83. data/lib/faraday/param_part.rb +0 -53
  84. data/lib/faraday/request/basic_authentication.rb +0 -20
  85. data/lib/faraday/request/multipart.rb +0 -99
  86. data/lib/faraday/request/retry.rb +0 -239
  87. data/lib/faraday/request/token_authentication.rb +0 -20
  88. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  89. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  90. data/spec/faraday/adapter/excon_spec.rb +0 -49
  91. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  92. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  93. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  94. data/spec/faraday/adapter/patron_spec.rb +0 -18
  95. data/spec/faraday/adapter/rack_spec.rb +0 -8
  96. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  97. data/spec/faraday/composite_read_io_spec.rb +0 -80
  98. data/spec/faraday/request/multipart_spec.rb +0 -274
  99. data/spec/faraday/request/retry_spec.rb +0 -242
  100. data/spec/faraday/response/middleware_spec.rb +0 -52
  101. data/spec/support/webmock_rack_app.rb +0 -68
@@ -30,7 +30,7 @@ module Faraday
30
30
  new_value = value
31
31
  end
32
32
 
33
- send("#{key}=", new_value) unless new_value.nil?
33
+ send(:"#{key}=", new_value) unless new_value.nil?
34
34
  end
35
35
  self
36
36
  end
@@ -38,7 +38,7 @@ module Faraday
38
38
  # Public
39
39
  def delete(key)
40
40
  value = send(key)
41
- send("#{key}=", nil)
41
+ send(:"#{key}=", nil)
42
42
  value
43
43
  end
44
44
 
@@ -57,7 +57,7 @@ module Faraday
57
57
  else
58
58
  other_value
59
59
  end
60
- send("#{key}=", new_value) unless new_value.nil?
60
+ send(:"#{key}=", new_value) unless new_value.nil?
61
61
  end
62
62
  self
63
63
  end
@@ -103,12 +103,10 @@ module Faraday
103
103
  end
104
104
 
105
105
  # Public
106
- def each_key
107
- return to_enum(:each_key) unless block_given?
106
+ def each_key(&block)
107
+ return to_enum(:each_key) unless block
108
108
 
109
- keys.each do |key|
110
- yield(key)
111
- end
109
+ keys.each(&block)
112
110
  end
113
111
 
114
112
  # Public
@@ -119,12 +117,10 @@ module Faraday
119
117
  alias has_key? key?
120
118
 
121
119
  # Public
122
- def each_value
123
- return to_enum(:each_value) unless block_given?
120
+ def each_value(&block)
121
+ return to_enum(:each_value) unless block
124
122
 
125
- values.each do |value|
126
- yield(value)
127
- end
123
+ values.each(&block)
128
124
  end
129
125
 
130
126
  # Public
@@ -172,12 +168,13 @@ module Faraday
172
168
  end
173
169
 
174
170
  def self.memoized(key, &block)
175
- unless block_given?
171
+ unless block
176
172
  raise ArgumentError, '#memoized must be called with a block'
177
173
  end
178
174
 
179
175
  memoized_attributes[key.to_sym] = block
180
176
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
177
+ remove_method(key) if method_defined?(key, false)
181
178
  def #{key}() self[:#{key}]; end
182
179
  RUBY
183
180
  end
@@ -7,7 +7,7 @@ module Faraday
7
7
  # middleware stack (heavily inspired by Rack).
8
8
  #
9
9
  # @example
10
- # Faraday::Connection.new(url: 'http://sushi.com') do |builder|
10
+ # Faraday::Connection.new(url: 'http://httpbingo.org') do |builder|
11
11
  # builder.request :url_encoded # Faraday::Request::UrlEncoded
12
12
  # builder.adapter :net_http # Faraday::Adapter::NetHttp
13
13
  # end
@@ -27,7 +27,7 @@ module Faraday
27
27
 
28
28
  attr_reader :name
29
29
 
30
- def initialize(klass, *args, &block)
30
+ ruby2_keywords def initialize(klass, *args, &block)
31
31
  @name = klass.to_s
32
32
  REGISTRY.set(klass) if klass.respond_to?(:name)
33
33
  @args = args
@@ -57,23 +57,22 @@ module Faraday
57
57
  end
58
58
  end
59
59
 
60
- def initialize(handlers = [], adapter = nil, &block)
61
- @adapter = adapter
62
- @handlers = handlers
63
- if block_given?
64
- build(&block)
65
- elsif @handlers.empty?
66
- # default stack, if nothing else is configured
67
- request :url_encoded
68
- self.adapter Faraday.default_adapter
69
- end
60
+ def initialize(&block)
61
+ @adapter = nil
62
+ @handlers = []
63
+ build(&block)
64
+ end
65
+
66
+ def initialize_dup(original)
67
+ super
68
+ @adapter = original.adapter
69
+ @handlers = original.handlers.dup
70
70
  end
71
71
 
72
- def build(options = {})
72
+ def build
73
73
  raise_if_locked
74
- @handlers.clear unless options[:keep]
75
- yield(self) if block_given?
76
- adapter(Faraday.default_adapter) unless @adapter
74
+ block_given? ? yield(self) : request(:url_encoded)
75
+ adapter(Faraday.default_adapter, **Faraday.default_adapter_options) unless @adapter
77
76
  end
78
77
 
79
78
  def [](idx)
@@ -89,7 +88,7 @@ module Faraday
89
88
  @handlers.frozen?
90
89
  end
91
90
 
92
- def use(klass, *args, &block)
91
+ ruby2_keywords def use(klass, *args, &block)
93
92
  if klass.is_a? Symbol
94
93
  use_symbol(Faraday::Middleware, klass, *args, &block)
95
94
  else
@@ -99,16 +98,16 @@ module Faraday
99
98
  end
100
99
  end
101
100
 
102
- def request(key, *args, &block)
101
+ ruby2_keywords def request(key, *args, &block)
103
102
  use_symbol(Faraday::Request, key, *args, &block)
104
103
  end
105
104
 
106
- def response(key, *args, &block)
105
+ ruby2_keywords def response(key, *args, &block)
107
106
  use_symbol(Faraday::Response, key, *args, &block)
108
107
  end
109
108
 
110
- def adapter(klass = NO_ARGUMENT, *args, &block)
111
- return @adapter if klass == NO_ARGUMENT
109
+ ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
110
+ return @adapter if klass == NO_ARGUMENT || klass.nil?
112
111
 
113
112
  klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
114
113
  @adapter = self.class::Handler.new(klass, *args, &block)
@@ -116,7 +115,7 @@ module Faraday
116
115
 
117
116
  ## methods to push onto the various positions in the stack:
118
117
 
119
- def insert(index, *args, &block)
118
+ ruby2_keywords def insert(index, *args, &block)
120
119
  raise_if_locked
121
120
  index = assert_index(index)
122
121
  handler = self.class::Handler.new(*args, &block)
@@ -125,12 +124,12 @@ module Faraday
125
124
 
126
125
  alias insert_before insert
127
126
 
128
- def insert_after(index, *args, &block)
127
+ ruby2_keywords def insert_after(index, *args, &block)
129
128
  index = assert_index(index)
130
129
  insert(index + 1, *args, &block)
131
130
  end
132
131
 
133
- def swap(index, *args, &block)
132
+ ruby2_keywords def swap(index, *args, &block)
134
133
  raise_if_locked
135
134
  index = assert_index(index)
136
135
  @handlers.delete_at(index)
@@ -163,6 +162,7 @@ module Faraday
163
162
  def app
164
163
  @app ||= begin
165
164
  lock!
165
+ ensure_adapter!
166
166
  to_app
167
167
  end
168
168
  end
@@ -181,12 +181,8 @@ module Faraday
181
181
  @adapter == other.adapter
182
182
  end
183
183
 
184
- def dup
185
- self.class.new(@handlers.dup, @adapter.dup)
186
- end
187
-
188
184
  # ENV Keys
189
- # :method - a symbolized request method (:get, :post)
185
+ # :http_method - a symbolized request HTTP method (:get, :post)
190
186
  # :body - the request body that will eventually be converted to a string.
191
187
  # :url - URI instance for the current request.
192
188
  # :status - HTTP response status code
@@ -207,7 +203,7 @@ module Faraday
207
203
  request.options.params_encoder
208
204
  )
209
205
 
210
- Env.new(request.method, request.body, exclusive_url,
206
+ Env.new(request.http_method, request.body, exclusive_url,
211
207
  request.options, request.headers, connection.ssl,
212
208
  connection.parallel_manager)
213
209
  end
@@ -215,6 +211,9 @@ module Faraday
215
211
  private
216
212
 
217
213
  LOCK_ERR = "can't modify middleware stack after making a request"
214
+ MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
215
+ "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
216
+ 'For more info, check https://lostisland.github.io/faraday/usage/.'
218
217
 
219
218
  def raise_if_locked
220
219
  raise StackLocked, LOCK_ERR if locked?
@@ -226,15 +225,19 @@ module Faraday
226
225
  raise 'Adapter should be set using the `adapter` method, not `use`'
227
226
  end
228
227
 
228
+ def ensure_adapter!
229
+ raise MISSING_ADAPTER_ERROR unless @adapter
230
+ end
231
+
229
232
  def adapter_set?
230
233
  !@adapter.nil?
231
234
  end
232
235
 
233
236
  def is_adapter?(klass) # rubocop:disable Naming/PredicateName
234
- klass.ancestors.include?(Faraday::Adapter)
237
+ klass <= Faraday::Adapter
235
238
  end
236
239
 
237
- def use_symbol(mod, key, *args, &block)
240
+ ruby2_keywords def use_symbol(mod, key, *args, &block)
238
241
  use(mod.lookup_middleware(key), *args, &block)
239
242
  end
240
243
 
@@ -4,50 +4,51 @@ module Faraday
4
4
  class Request
5
5
  # Request middleware for the Authorization HTTP header
6
6
  class Authorization < Faraday::Middleware
7
- KEY = 'Authorization' unless defined? KEY
8
-
9
- # @param type [String, Symbol]
10
- # @param token [String, Symbol, Hash]
11
- # @return [String] a header value
12
- def self.header(type, token)
13
- case token
14
- when String, Symbol
15
- "#{type} #{token}"
16
- when Hash
17
- build_hash(type.to_s, token)
18
- else
19
- raise ArgumentError,
20
- "Can't build an Authorization #{type}" \
21
- "header from #{token.inspect}"
22
- end
23
- end
24
-
25
- # @param type [String]
26
- # @param hash [Hash]
27
- # @return [String] type followed by comma-separated key=value pairs
28
- # @api private
29
- def self.build_hash(type, hash)
30
- comma = ', '
31
- values = []
32
- hash.each do |key, value|
33
- values << "#{key}=#{value.to_s.inspect}"
34
- end
35
- "#{type} #{values * comma}"
36
- end
7
+ KEY = 'Authorization'
37
8
 
38
9
  # @param app [#call]
39
10
  # @param type [String, Symbol] Type of Authorization
40
- # @param token [String, Symbol, Hash] Token value for the Authorization
41
- def initialize(app, type, token)
42
- @header_value = self.class.header(type, token)
11
+ # @param params [Array<String, Proc, #call>] parameters to build the Authorization header.
12
+ # If the type is `:basic`, then these can be a login and password pair.
13
+ # Otherwise, a single value is expected that will be appended after the type.
14
+ # This value can be a proc or an object responding to `.call`, in which case
15
+ # it will be invoked on each request.
16
+ def initialize(app, type, *params)
17
+ @type = type
18
+ @params = params
43
19
  super(app)
44
20
  end
45
21
 
46
22
  # @param env [Faraday::Env]
47
- def call(env)
48
- env.request_headers[KEY] = @header_value unless env.request_headers[KEY]
49
- @app.call(env)
23
+ def on_request(env)
24
+ return if env.request_headers[KEY]
25
+
26
+ env.request_headers[KEY] = header_from(@type, env, *@params)
27
+ end
28
+
29
+ private
30
+
31
+ # @param type [String, Symbol]
32
+ # @param env [Faraday::Env]
33
+ # @param params [Array]
34
+ # @return [String] a header value
35
+ def header_from(type, env, *params)
36
+ if type.to_s.casecmp('basic').zero? && params.size == 2
37
+ Utils.basic_header_from(*params)
38
+ elsif params.size != 1
39
+ raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
40
+ else
41
+ value = params.first
42
+ if (value.is_a?(Proc) && value.arity == 1) || (value.respond_to?(:call) && value.method(:call).arity == 1)
43
+ value = value.call(env)
44
+ elsif value.is_a?(Proc) || value.respond_to?(:call)
45
+ value = value.call
46
+ end
47
+ "#{type} #{value}"
48
+ end
50
49
  end
51
50
  end
52
51
  end
53
52
  end
53
+
54
+ Faraday::Request.register_middleware(authorization: Faraday::Request::Authorization)
@@ -5,12 +5,14 @@ module Faraday
5
5
  # Middleware for instrumenting Requests.
6
6
  class Instrumentation < Faraday::Middleware
7
7
  # Options class used in Request::Instrumentation class.
8
- class Options < Faraday::Options.new(:name, :instrumenter)
8
+ Options = Faraday::Options.new(:name, :instrumenter) do
9
+ remove_method :name
9
10
  # @return [String]
10
11
  def name
11
12
  self[:name] ||= 'request.faraday'
12
13
  end
13
14
 
15
+ remove_method :instrumenter
14
16
  # @return [Class]
15
17
  def instrumenter
16
18
  self[:instrumenter] ||= ActiveSupport::Notifications
@@ -52,3 +54,5 @@ module Faraday
52
54
  end
53
55
  end
54
56
  end
57
+
58
+ Faraday::Request.register_middleware(instrumentation: Faraday::Request::Instrumentation)
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Faraday
6
+ class Request
7
+ # Request middleware that encodes the body as JSON.
8
+ #
9
+ # Processes only requests with matching Content-type or those without a type.
10
+ # If a request doesn't have a type but has a body, it sets the Content-type
11
+ # to JSON MIME-type.
12
+ #
13
+ # Doesn't try to encode bodies that already are in string form.
14
+ class Json < Middleware
15
+ MIME_TYPE = 'application/json'
16
+ MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?json$}
17
+
18
+ def on_request(env)
19
+ match_content_type(env) do |data|
20
+ env[:body] = encode(data)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def encode(data)
27
+ if options[:encoder].is_a?(Array) && options[:encoder].size >= 2
28
+ options[:encoder][0].public_send(options[:encoder][1], data)
29
+ elsif options[:encoder].respond_to?(:dump)
30
+ options[:encoder].dump(data)
31
+ else
32
+ ::JSON.generate(data)
33
+ end
34
+ end
35
+
36
+ def match_content_type(env)
37
+ return unless process_request?(env)
38
+
39
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
40
+ yield env[:body] unless env[:body].respond_to?(:to_str)
41
+ end
42
+
43
+ def process_request?(env)
44
+ type = request_type(env)
45
+ body?(env) && (type.empty? || type.match?(MIME_TYPE_REGEX))
46
+ end
47
+
48
+ def body?(env)
49
+ body = env[:body]
50
+ case body
51
+ when true, false
52
+ true
53
+ when nil
54
+ # NOTE: nil can be converted to `"null"`, but this middleware doesn't process `nil` for the compatibility.
55
+ false
56
+ else
57
+ !(body.respond_to?(:to_str) && body.empty?)
58
+ end
59
+ end
60
+
61
+ def request_type(env)
62
+ type = env[:request_headers][CONTENT_TYPE].to_s
63
+ type = type.split(';', 2).first if type.index(';')
64
+ type
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ Faraday::Request.register_middleware(json: Faraday::Request::Json)
@@ -4,7 +4,9 @@ module Faraday
4
4
  class Request
5
5
  # Middleware for supporting urlencoded requests.
6
6
  class UrlEncoded < Faraday::Middleware
7
- CONTENT_TYPE = 'Content-Type' unless defined? CONTENT_TYPE
7
+ unless defined?(::Faraday::Request::UrlEncoded::CONTENT_TYPE)
8
+ CONTENT_TYPE = 'Content-Type'
9
+ end
8
10
 
9
11
  class << self
10
12
  attr_accessor :mime_type
@@ -29,7 +31,9 @@ module Faraday
29
31
  return unless process_request?(env)
30
32
 
31
33
  env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
32
- yield(env.body) unless env.body.respond_to?(:to_str)
34
+ return if env.body.respond_to?(:to_str) || env.body.respond_to?(:read)
35
+
36
+ yield(env.body)
33
37
  end
34
38
 
35
39
  # @param env [Faraday::Env]
@@ -52,3 +56,5 @@ module Faraday
52
56
  end
53
57
  end
54
58
  end
59
+
60
+ Faraday::Request.register_middleware(url_encoded: Faraday::Request::UrlEncoded)
@@ -12,7 +12,7 @@ module Faraday
12
12
  # req.body = 'abc'
13
13
  # end
14
14
  #
15
- # @!attribute method
15
+ # @!attribute http_method
16
16
  # @return [Symbol] the HTTP method of the Request
17
17
  # @!attribute path
18
18
  # @return [URI, String] the path
@@ -21,30 +21,16 @@ module Faraday
21
21
  # @!attribute headers
22
22
  # @return [Faraday::Utils::Headers] headers
23
23
  # @!attribute body
24
- # @return [Hash] body
24
+ # @return [String] body
25
25
  # @!attribute options
26
26
  # @return [RequestOptions] options
27
- #
28
- # rubocop:disable Style/StructInheritance
29
- class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
30
- # rubocop:enable Style/StructInheritance
31
-
27
+ Request = Struct.new(:http_method, :path, :params, :headers, :body, :options) do
32
28
  extend MiddlewareRegistry
33
29
 
34
- register_middleware File.expand_path('request', __dir__),
35
- url_encoded: [:UrlEncoded, 'url_encoded'],
36
- multipart: [:Multipart, 'multipart'],
37
- retry: [:Retry, 'retry'],
38
- authorization: [:Authorization, 'authorization'],
39
- basic_auth: [
40
- :BasicAuthentication,
41
- 'basic_authentication'
42
- ],
43
- token_auth: [
44
- :TokenAuthentication,
45
- 'token_authentication'
46
- ],
47
- instrumentation: [:Instrumentation, 'instrumentation']
30
+ alias_method :member_get, :[]
31
+ private :member_get
32
+ alias_method :member_set, :[]=
33
+ private :member_set
48
34
 
49
35
  # @param request_method [String]
50
36
  # @yield [request] for block customization, if block given
@@ -56,6 +42,7 @@ module Faraday
56
42
  end
57
43
  end
58
44
 
45
+ remove_method :params=
59
46
  # Replace params, preserving the existing hash type.
60
47
  #
61
48
  # @param hash [Hash] new params
@@ -63,10 +50,11 @@ module Faraday
63
50
  if params
64
51
  params.replace hash
65
52
  else
66
- super
53
+ member_set(:params, hash)
67
54
  end
68
55
  end
69
56
 
57
+ remove_method :headers=
70
58
  # Replace request headers, preserving the existing hash type.
71
59
  #
72
60
  # @param hash [Hash] new headers
@@ -74,7 +62,7 @@ module Faraday
74
62
  if headers
75
63
  headers.replace hash
76
64
  else
77
- super
65
+ member_set(:headers, hash)
78
66
  end
79
67
  end
80
68
 
@@ -116,7 +104,7 @@ module Faraday
116
104
  # @return [Hash] the hash ready to be serialized in Marshal.
117
105
  def marshal_dump
118
106
  {
119
- method: method,
107
+ http_method: http_method,
120
108
  body: body,
121
109
  headers: headers,
122
110
  path: path,
@@ -129,18 +117,23 @@ module Faraday
129
117
  # Restores the instance variables according to the +serialised+.
130
118
  # @param serialised [Hash] the serialised object.
131
119
  def marshal_load(serialised)
132
- self.method = serialised[:method]
133
- self.body = serialised[:body]
120
+ self.http_method = serialised[:http_method]
121
+ self.body = serialised[:body]
134
122
  self.headers = serialised[:headers]
135
- self.path = serialised[:path]
136
- self.params = serialised[:params]
123
+ self.path = serialised[:path]
124
+ self.params = serialised[:params]
137
125
  self.options = serialised[:options]
138
126
  end
139
127
 
140
128
  # @return [Env] the Env for this Request
141
129
  def to_env(connection)
142
- Env.new(method, body, connection.build_exclusive_url(path, params),
130
+ Env.new(http_method, body, connection.build_exclusive_url(path, params),
143
131
  options, headers, connection.ssl, connection.parallel_manager)
144
132
  end
145
133
  end
146
134
  end
135
+
136
+ require 'faraday/request/authorization'
137
+ require 'faraday/request/instrumentation'
138
+ require 'faraday/request/json'
139
+ require 'faraday/request/url_encoded'
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Faraday
6
+ class Response
7
+ # Parse response bodies as JSON.
8
+ class Json < Middleware
9
+ def initialize(app = nil, parser_options: nil, content_type: /\bjson$/, preserve_raw: false)
10
+ super(app)
11
+ @parser_options = parser_options
12
+ @content_types = Array(content_type)
13
+ @preserve_raw = preserve_raw
14
+
15
+ process_parser_options
16
+ end
17
+
18
+ def on_complete(env)
19
+ process_response(env) if parse_response?(env)
20
+ end
21
+
22
+ private
23
+
24
+ def process_response(env)
25
+ env[:raw_body] = env[:body] if @preserve_raw
26
+ env[:body] = parse(env[:body])
27
+ rescue StandardError, SyntaxError => e
28
+ raise Faraday::ParsingError.new(e, env[:response])
29
+ end
30
+
31
+ def parse(body)
32
+ return if body.strip.empty?
33
+
34
+ decoder, method_name = @decoder_options
35
+
36
+ decoder.public_send(method_name, body, @parser_options || {})
37
+ end
38
+
39
+ def parse_response?(env)
40
+ process_response_type?(env) &&
41
+ env[:body].respond_to?(:to_str)
42
+ end
43
+
44
+ def process_response_type?(env)
45
+ type = response_type(env)
46
+ @content_types.empty? || @content_types.any? do |pattern|
47
+ pattern.is_a?(Regexp) ? type.match?(pattern) : type == pattern
48
+ end
49
+ end
50
+
51
+ def response_type(env)
52
+ type = env[:response_headers][CONTENT_TYPE].to_s
53
+ type = type.split(';', 2).first if type.index(';')
54
+ type
55
+ end
56
+
57
+ def process_parser_options
58
+ @decoder_options = @parser_options&.delete(:decoder)
59
+
60
+ @decoder_options =
61
+ if @decoder_options.is_a?(Array) && @decoder_options.size >= 2
62
+ @decoder_options.slice(0, 2)
63
+ elsif @decoder_options.respond_to?(:load)
64
+ [@decoder_options, :load]
65
+ else
66
+ [::JSON, :parse]
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ Faraday::Response.register_middleware(json: Faraday::Response::Json)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require 'logger'
4
5
  require 'faraday/logging/formatter'
5
6
 
6
7
  module Faraday
@@ -11,10 +12,7 @@ module Faraday
11
12
  class Logger < Middleware
12
13
  def initialize(app, logger = nil, options = {})
13
14
  super(app)
14
- logger ||= begin
15
- require 'logger'
16
- ::Logger.new($stdout)
17
- end
15
+ logger ||= ::Logger.new($stdout)
18
16
  formatter_class = options.delete(:formatter) || Logging::Formatter
19
17
  @formatter = formatter_class.new(logger: logger, options: options)
20
18
  yield @formatter if block_given?
@@ -28,6 +26,12 @@ module Faraday
28
26
  def on_complete(env)
29
27
  @formatter.response(env)
30
28
  end
29
+
30
+ def on_error(exc)
31
+ @formatter.exception(exc) if @formatter.respond_to?(:exception)
32
+ end
31
33
  end
32
34
  end
33
35
  end
36
+
37
+ Faraday::Response.register_middleware(logger: Faraday::Response::Logger)