faraday 1.0.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
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)