faraday 0.15.0 → 1.10.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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +380 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +17 -345
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +97 -0
  7. data/examples/client_test.rb +118 -0
  8. data/lib/faraday/adapter/test.rb +118 -69
  9. data/lib/faraday/adapter/typhoeus.rb +4 -1
  10. data/lib/faraday/adapter.rb +72 -22
  11. data/lib/faraday/adapter_registry.rb +30 -0
  12. data/lib/faraday/autoload.rb +39 -36
  13. data/lib/faraday/connection.rb +343 -185
  14. data/lib/faraday/dependency_loader.rb +37 -0
  15. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  16. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  17. data/lib/faraday/error.rb +118 -38
  18. data/lib/faraday/logging/formatter.rb +105 -0
  19. data/lib/faraday/methods.rb +6 -0
  20. data/lib/faraday/middleware.rb +19 -25
  21. data/lib/faraday/middleware_registry.rb +129 -0
  22. data/lib/faraday/options/connection_options.rb +22 -0
  23. data/lib/faraday/options/env.rb +181 -0
  24. data/lib/faraday/options/proxy_options.rb +32 -0
  25. data/lib/faraday/options/request_options.rb +22 -0
  26. data/lib/faraday/options/ssl_options.rb +59 -0
  27. data/lib/faraday/options.rb +39 -193
  28. data/lib/faraday/parameters.rb +4 -196
  29. data/lib/faraday/rack_builder.rb +77 -65
  30. data/lib/faraday/request/authorization.rb +51 -30
  31. data/lib/faraday/request/basic_authentication.rb +14 -7
  32. data/lib/faraday/request/instrumentation.rb +45 -27
  33. data/lib/faraday/request/json.rb +55 -0
  34. data/lib/faraday/request/token_authentication.rb +15 -10
  35. data/lib/faraday/request/url_encoded.rb +43 -23
  36. data/lib/faraday/request.rb +93 -32
  37. data/lib/faraday/response/json.rb +54 -0
  38. data/lib/faraday/response/logger.rb +20 -69
  39. data/lib/faraday/response/raise_error.rb +49 -14
  40. data/lib/faraday/response.rb +29 -23
  41. data/lib/faraday/utils/headers.rb +139 -0
  42. data/lib/faraday/utils/params_hash.rb +61 -0
  43. data/lib/faraday/utils.rb +38 -247
  44. data/lib/faraday/version.rb +5 -0
  45. data/lib/faraday.rb +134 -189
  46. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  47. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  48. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  49. data/spec/faraday/adapter/excon_spec.rb +49 -0
  50. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  51. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  52. data/spec/faraday/adapter/patron_spec.rb +18 -0
  53. data/spec/faraday/adapter/rack_spec.rb +8 -0
  54. data/spec/faraday/adapter/test_spec.rb +377 -0
  55. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  56. data/spec/faraday/adapter_registry_spec.rb +28 -0
  57. data/spec/faraday/adapter_spec.rb +55 -0
  58. data/spec/faraday/composite_read_io_spec.rb +80 -0
  59. data/spec/faraday/connection_spec.rb +736 -0
  60. data/spec/faraday/error_spec.rb +60 -0
  61. data/spec/faraday/middleware_spec.rb +52 -0
  62. data/spec/faraday/options/env_spec.rb +70 -0
  63. data/spec/faraday/options/options_spec.rb +297 -0
  64. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  65. data/spec/faraday/options/request_options_spec.rb +19 -0
  66. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  67. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  68. data/spec/faraday/rack_builder_spec.rb +345 -0
  69. data/spec/faraday/request/authorization_spec.rb +96 -0
  70. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  71. data/spec/faraday/request/json_spec.rb +111 -0
  72. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  73. data/spec/faraday/request_spec.rb +120 -0
  74. data/spec/faraday/response/json_spec.rb +119 -0
  75. data/spec/faraday/response/logger_spec.rb +220 -0
  76. data/spec/faraday/response/middleware_spec.rb +68 -0
  77. data/spec/faraday/response/raise_error_spec.rb +169 -0
  78. data/spec/faraday/response_spec.rb +75 -0
  79. data/spec/faraday/utils/headers_spec.rb +82 -0
  80. data/spec/faraday/utils_spec.rb +56 -0
  81. data/spec/faraday_spec.rb +37 -0
  82. data/spec/spec_helper.rb +132 -0
  83. data/spec/support/disabling_stub.rb +14 -0
  84. data/spec/support/fake_safe_buffer.rb +15 -0
  85. data/spec/support/helper_methods.rb +133 -0
  86. data/spec/support/shared_examples/adapter.rb +105 -0
  87. data/spec/support/shared_examples/params_encoder.rb +18 -0
  88. data/spec/support/shared_examples/request_method.rb +262 -0
  89. data/spec/support/streaming_response_checker.rb +35 -0
  90. data/spec/support/webmock_rack_app.rb +68 -0
  91. metadata +222 -29
  92. data/lib/faraday/adapter/em_http.rb +0 -243
  93. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  94. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  95. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  96. data/lib/faraday/adapter/excon.rb +0 -79
  97. data/lib/faraday/adapter/httpclient.rb +0 -128
  98. data/lib/faraday/adapter/net_http.rb +0 -137
  99. data/lib/faraday/adapter/net_http_persistent.rb +0 -63
  100. data/lib/faraday/adapter/patron.rb +0 -100
  101. data/lib/faraday/adapter/rack.rb +0 -58
  102. data/lib/faraday/request/multipart.rb +0 -68
  103. data/lib/faraday/request/retry.rb +0 -211
  104. data/lib/faraday/upload_io.rb +0 -67
@@ -1,12 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby2_keywords'
4
+ require 'faraday/adapter_registry'
5
+
1
6
  module Faraday
2
7
  # A Builder that processes requests into responses by passing through an inner
3
8
  # middleware stack (heavily inspired by Rack).
4
9
  #
5
- # Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
10
+ # @example
11
+ # Faraday::Connection.new(url: 'http://sushi.com') do |builder|
6
12
  # builder.request :url_encoded # Faraday::Request::UrlEncoded
7
13
  # builder.adapter :net_http # Faraday::Adapter::NetHttp
8
14
  # end
9
15
  class RackBuilder
16
+ # Used to detect missing arguments
17
+ NO_ARGUMENT = Object.new
18
+
10
19
  attr_accessor :handlers
11
20
 
12
21
  # Error raised when trying to modify the stack after calling `lock!`
@@ -15,28 +24,28 @@ module Faraday
15
24
  # borrowed from ActiveSupport::Dependencies::Reference &
16
25
  # ActionDispatch::MiddlewareStack::Middleware
17
26
  class Handler
18
- @@constants_mutex = Mutex.new
19
- @@constants = Hash.new { |h, k|
20
- value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
21
- @@constants_mutex.synchronize { h[k] = value }
22
- }
27
+ REGISTRY = Faraday::AdapterRegistry.new
23
28
 
24
29
  attr_reader :name
25
30
 
26
- def initialize(klass, *args, &block)
31
+ ruby2_keywords def initialize(klass, *args, &block)
27
32
  @name = klass.to_s
28
- if klass.respond_to?(:name)
29
- @@constants_mutex.synchronize { @@constants[@name] = klass }
30
- end
31
- @args, @block = args, block
33
+ REGISTRY.set(klass) if klass.respond_to?(:name)
34
+ @args = args
35
+ @block = block
32
36
  end
33
37
 
34
- def klass() @@constants[@name] end
35
- def inspect() @name end
38
+ def klass
39
+ REGISTRY.get(@name)
40
+ end
41
+
42
+ def inspect
43
+ @name
44
+ end
36
45
 
37
46
  def ==(other)
38
47
  if other.is_a? Handler
39
- self.name == other.name
48
+ name == other.name
40
49
  elsif other.respond_to? :name
41
50
  klass == other
42
51
  else
@@ -44,18 +53,19 @@ module Faraday
44
53
  end
45
54
  end
46
55
 
47
- def build(app)
56
+ def build(app = nil)
48
57
  klass.new(app, *@args, &@block)
49
58
  end
50
59
  end
51
60
 
52
- def initialize(handlers = [])
61
+ def initialize(handlers = [], adapter = nil, &block)
62
+ @adapter = adapter
53
63
  @handlers = handlers
54
64
  if block_given?
55
- build(&Proc.new)
65
+ build(&block)
56
66
  elsif @handlers.empty?
57
67
  # default stack, if nothing else is configured
58
- self.request :url_encoded
68
+ request :url_encoded
59
69
  self.adapter Faraday.default_adapter
60
70
  end
61
71
  end
@@ -64,13 +74,14 @@ module Faraday
64
74
  raise_if_locked
65
75
  @handlers.clear unless options[:keep]
66
76
  yield(self) if block_given?
77
+ adapter(Faraday.default_adapter) unless @adapter
67
78
  end
68
79
 
69
80
  def [](idx)
70
81
  @handlers[idx]
71
82
  end
72
83
 
73
- # Locks the middleware stack to ensure no further modifications are possible.
84
+ # Locks the middleware stack to ensure no further modifications are made.
74
85
  def lock!
75
86
  @handlers.freeze
76
87
  end
@@ -79,46 +90,48 @@ module Faraday
79
90
  @handlers.frozen?
80
91
  end
81
92
 
82
- def use(klass, *args, &block)
93
+ ruby2_keywords def use(klass, *args, &block)
83
94
  if klass.is_a? Symbol
84
95
  use_symbol(Faraday::Middleware, klass, *args, &block)
85
96
  else
86
97
  raise_if_locked
87
- warn_middleware_after_adapter if adapter_set?
98
+ raise_if_adapter(klass)
88
99
  @handlers << self.class::Handler.new(klass, *args, &block)
89
100
  end
90
101
  end
91
102
 
92
- def request(key, *args, &block)
103
+ ruby2_keywords def request(key, *args, &block)
93
104
  use_symbol(Faraday::Request, key, *args, &block)
94
105
  end
95
106
 
96
- def response(key, *args, &block)
107
+ ruby2_keywords def response(key, *args, &block)
97
108
  use_symbol(Faraday::Response, key, *args, &block)
98
109
  end
99
110
 
100
- def adapter(key, *args, &block)
101
- use_symbol(Faraday::Adapter, key, *args, &block)
111
+ ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
112
+ return @adapter if klass == NO_ARGUMENT
113
+
114
+ klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
115
+ @adapter = self.class::Handler.new(klass, *args, &block)
102
116
  end
103
117
 
104
118
  ## methods to push onto the various positions in the stack:
105
119
 
106
- def insert(index, *args, &block)
120
+ ruby2_keywords def insert(index, *args, &block)
107
121
  raise_if_locked
108
122
  index = assert_index(index)
109
- warn_middleware_after_adapter if inserting_after_adapter?(index)
110
123
  handler = self.class::Handler.new(*args, &block)
111
124
  @handlers.insert(index, handler)
112
125
  end
113
126
 
114
- alias_method :insert_before, :insert
127
+ alias insert_before insert
115
128
 
116
- def insert_after(index, *args, &block)
129
+ ruby2_keywords def insert_after(index, *args, &block)
117
130
  index = assert_index(index)
118
131
  insert(index + 1, *args, &block)
119
132
  end
120
133
 
121
- def swap(index, *args, &block)
134
+ ruby2_keywords def swap(index, *args, &block)
122
135
  raise_if_locked
123
136
  index = assert_index(index)
124
137
  @handlers.delete_at(index)
@@ -133,13 +146,11 @@ module Faraday
133
146
  # Processes a Request into a Response by passing it through this Builder's
134
147
  # middleware stack.
135
148
  #
136
- # connection - Faraday::Connection
137
- # request - Faraday::Request
149
+ # @param connection [Faraday::Connection]
150
+ # @param request [Faraday::Request]
138
151
  #
139
- # Returns a Faraday::Response.
152
+ # @return [Faraday::Response]
140
153
  def build_response(connection, request)
141
- warn 'WARNING: No adapter was configured for this request' unless adapter_set?
142
-
143
154
  app.call(build_env(connection, request))
144
155
  end
145
156
 
@@ -153,30 +164,30 @@ module Faraday
153
164
  def app
154
165
  @app ||= begin
155
166
  lock!
156
- to_app(lambda { |env|
157
- response = Response.new
158
- env.response = response
159
- response.finish(env) unless env.parallel?
160
- response
161
- })
167
+ to_app
162
168
  end
163
169
  end
164
170
 
165
- def to_app(inner_app)
171
+ def to_app
166
172
  # last added handler is the deepest and thus closest to the inner app
167
- @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
173
+ # adapter is always the last one
174
+ @handlers.reverse.inject(@adapter.build) do |app, handler|
175
+ handler.build(app)
176
+ end
168
177
  end
169
178
 
170
179
  def ==(other)
171
- other.is_a?(self.class) && @handlers == other.handlers
180
+ other.is_a?(self.class) &&
181
+ @handlers == other.handlers &&
182
+ @adapter == other.adapter
172
183
  end
173
184
 
174
185
  def dup
175
- self.class.new(@handlers.dup)
186
+ self.class.new(@handlers.dup, @adapter.dup)
176
187
  end
177
188
 
178
189
  # ENV Keys
179
- # :method - a symbolized request method (:get, :post)
190
+ # :http_method - a symbolized request HTTP method (:get, :post)
180
191
  # :body - the request body that will eventually be converted to a string.
181
192
  # :url - URI instance for the current request.
182
193
  # :status - HTTP response status code
@@ -192,45 +203,46 @@ module Faraday
192
203
  # :password - Proxy server password
193
204
  # :ssl - Hash of options for configuring SSL requests.
194
205
  def build_env(connection, request)
195
- Env.new(request.method, request.body,
196
- connection.build_exclusive_url(request.path, request.params, request.options.params_encoder),
197
- request.options, request.headers, connection.ssl,
198
- connection.parallel_manager)
206
+ exclusive_url = connection.build_exclusive_url(
207
+ request.path, request.params,
208
+ request.options.params_encoder
209
+ )
210
+
211
+ Env.new(request.http_method, request.body, exclusive_url,
212
+ request.options, request.headers, connection.ssl,
213
+ connection.parallel_manager)
199
214
  end
200
215
 
201
216
  private
202
217
 
218
+ LOCK_ERR = "can't modify middleware stack after making a request"
219
+
203
220
  def raise_if_locked
204
- raise StackLocked, "can't modify middleware stack after making a request" if locked?
221
+ raise StackLocked, LOCK_ERR if locked?
205
222
  end
206
223
 
207
- def warn_middleware_after_adapter
208
- warn "WARNING: Unexpected middleware set after the adapter. " \
209
- "This won't be supported from Faraday 1.0."
210
- end
224
+ def raise_if_adapter(klass)
225
+ return unless is_adapter?(klass)
211
226
 
212
- def adapter_set?
213
- @handlers.any? { |handler| is_adapter?(handler) }
227
+ raise 'Adapter should be set using the `adapter` method, not `use`'
214
228
  end
215
229
 
216
- def inserting_after_adapter?(index)
217
- adapter_index = @handlers.find_index { |handler| is_adapter?(handler) }
218
- return false if adapter_index.nil?
219
-
220
- index > adapter_index
230
+ def adapter_set?
231
+ !@adapter.nil?
221
232
  end
222
233
 
223
- def is_adapter?(handler)
224
- handler.klass.ancestors.include? Faraday::Adapter
234
+ def is_adapter?(klass) # rubocop:disable Naming/PredicateName
235
+ klass <= Faraday::Adapter
225
236
  end
226
237
 
227
- def use_symbol(mod, key, *args, &block)
238
+ ruby2_keywords def use_symbol(mod, key, *args, &block)
228
239
  use(mod.lookup_middleware(key), *args, &block)
229
240
  end
230
241
 
231
242
  def assert_index(index)
232
243
  idx = index.is_a?(Integer) ? index : @handlers.index(index)
233
244
  raise "No such handler: #{index.inspect}" unless idx
245
+
234
246
  idx
235
247
  end
236
248
  end
@@ -1,41 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
1
5
  module Faraday
2
- class Request::Authorization < Faraday::Middleware
3
- KEY = "Authorization".freeze unless defined? KEY
6
+ class Request
7
+ # Request middleware for the Authorization HTTP header
8
+ class Authorization < Faraday::Middleware
9
+ unless defined?(::Faraday::Request::Authorization::KEY)
10
+ KEY = 'Authorization'
11
+ end
4
12
 
5
- # Public
6
- def self.header(type, token)
7
- case token
8
- when String, Symbol
9
- "#{type} #{token}"
10
- when Hash
11
- build_hash(type.to_s, token)
12
- else
13
- raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
13
+ # @param type [String, Symbol]
14
+ # @param token [String, Symbol, Hash]
15
+ # @return [String] a header value
16
+ def self.header(type, token)
17
+ case token
18
+ when String, Symbol, Proc
19
+ token = token.call if token.is_a?(Proc)
20
+ "#{type} #{token}"
21
+ when Hash
22
+ build_hash(type.to_s, token)
23
+ else
24
+ raise ArgumentError,
25
+ "Can't build an Authorization #{type}" \
26
+ "header from #{token.inspect}"
27
+ end
14
28
  end
15
- end
16
29
 
17
- # Internal
18
- def self.build_hash(type, hash)
19
- comma = ", "
20
- values = []
21
- hash.each do |key, value|
22
- values << "#{key}=#{value.to_s.inspect}"
30
+ # @param type [String]
31
+ # @param hash [Hash]
32
+ # @return [String] type followed by comma-separated key=value pairs
33
+ # @api private
34
+ def self.build_hash(type, hash)
35
+ comma = ', '
36
+ values = []
37
+ hash.each do |key, value|
38
+ value = value.call if value.is_a?(Proc)
39
+ values << "#{key}=#{value.to_s.inspect}"
40
+ end
41
+ "#{type} #{values * comma}"
23
42
  end
24
- "#{type} #{values * comma}"
25
- end
26
43
 
27
- def initialize(app, type, token)
28
- @header_value = self.class.header(type, token)
29
- super(app)
30
- end
44
+ # @param app [#call]
45
+ # @param type [String, Symbol] Type of Authorization
46
+ # @param param [String, Symbol, Hash, Proc] parameter to build the Authorization header.
47
+ # This value can be a proc, in which case it will be invoked on each request.
48
+ def initialize(app, type, param)
49
+ @type = type
50
+ @param = param
51
+ super(app)
52
+ end
31
53
 
32
- # Public
33
- def call(env)
34
- unless env.request_headers[KEY]
35
- env.request_headers[KEY] = @header_value
54
+ # @param env [Faraday::Env]
55
+ def on_request(env)
56
+ return if env.request_headers[KEY]
57
+
58
+ env.request_headers[KEY] = self.class.header(@type, @param)
36
59
  end
37
- @app.call(env)
38
60
  end
39
61
  end
40
62
  end
41
-
@@ -1,13 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module Faraday
4
- class Request::BasicAuthentication < Request.load_middleware(:authorization)
5
- # Public
6
- def self.header(login, pass)
7
- value = Base64.encode64([login, pass].join(':'))
8
- value.gsub!("\n", '')
9
- super(:Basic, value)
6
+ class Request
7
+ # Authorization middleware for Basic Authentication.
8
+ class BasicAuthentication < load_middleware(:authorization)
9
+ # @param login [String]
10
+ # @param pass [String]
11
+ #
12
+ # @return [String] a Basic Authentication header line
13
+ def self.header(login, pass)
14
+ value = Base64.encode64([login, pass].join(':'))
15
+ value.delete!("\n")
16
+ super(:Basic, value)
17
+ end
10
18
  end
11
19
  end
12
20
  end
13
-
@@ -1,35 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::Instrumentation < Faraday::Middleware
3
- class Options < Faraday::Options.new(:name, :instrumenter)
4
- def name
5
- self[:name] ||= 'request.faraday'
6
- end
4
+ class Request
5
+ # Middleware for instrumenting Requests.
6
+ class Instrumentation < Faraday::Middleware
7
+ # Options class used in Request::Instrumentation class.
8
+ class Options < Faraday::Options.new(:name, :instrumenter)
9
+ # @return [String]
10
+ def name
11
+ self[:name] ||= 'request.faraday'
12
+ end
7
13
 
8
- def instrumenter
9
- self[:instrumenter] ||= ActiveSupport::Notifications
14
+ # @return [Class]
15
+ def instrumenter
16
+ self[:instrumenter] ||= ActiveSupport::Notifications
17
+ end
10
18
  end
11
- end
12
19
 
13
- # Public: Instruments requests using Active Support.
14
- #
15
- # Measures time spent only for synchronous requests.
16
- #
17
- # Examples
18
- #
19
- # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
20
- # url = env[:url]
21
- # http_method = env[:method].to_s.upcase
22
- # duration = ends - starts
23
- # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
24
- # end
25
- def initialize(app, options = nil)
26
- super(app)
27
- @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
28
- end
20
+ # Instruments requests using Active Support.
21
+ #
22
+ # Measures time spent only for synchronous requests.
23
+ #
24
+ # @example Using ActiveSupport::Notifications to measure time spent
25
+ # for Faraday requests.
26
+ # ActiveSupport::Notifications
27
+ # .subscribe('request.faraday') do |name, starts, ends, _, env|
28
+ # url = env[:url]
29
+ # http_method = env[:method].to_s.upcase
30
+ # duration = ends - starts
31
+ # $stderr.puts '[%s] %s %s (%.3f s)' %
32
+ # [url.host, http_method, url.request_uri, duration]
33
+ # end
34
+ # @param app [#call]
35
+ # @param options [nil, Hash] Options hash
36
+ # @option options [String] :name ('request.faraday')
37
+ # Name of the instrumenter
38
+ # @option options [Class] :instrumenter (ActiveSupport::Notifications)
39
+ # Active Support instrumenter class.
40
+ def initialize(app, options = nil)
41
+ super(app)
42
+ @name, @instrumenter = Options.from(options)
43
+ .values_at(:name, :instrumenter)
44
+ end
29
45
 
30
- def call(env)
31
- @instrumenter.instrument(@name, env) do
32
- @app.call(env)
46
+ # @param env [Faraday::Env]
47
+ def call(env)
48
+ @instrumenter.instrument(@name, env) do
49
+ @app.call(env)
50
+ end
33
51
  end
34
52
  end
35
53
  end
@@ -0,0 +1,55 @@
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$}.freeze
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
+ ::JSON.generate(data)
28
+ end
29
+
30
+ def match_content_type(env)
31
+ return unless process_request?(env)
32
+
33
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
34
+ yield env[:body] unless env[:body].respond_to?(:to_str)
35
+ end
36
+
37
+ def process_request?(env)
38
+ type = request_type(env)
39
+ body?(env) && (type.empty? || type.match?(MIME_TYPE_REGEX))
40
+ end
41
+
42
+ def body?(env)
43
+ (body = env[:body]) && !(body.respond_to?(:to_str) && body.empty?)
44
+ end
45
+
46
+ def request_type(env)
47
+ type = env[:request_headers][CONTENT_TYPE].to_s
48
+ type = type.split(';', 2).first if type.index(';')
49
+ type
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ Faraday::Request.register_middleware(json: Faraday::Request::Json)
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::TokenAuthentication < Request.load_middleware(:authorization)
3
- # Public
4
- def self.header(token, options = nil)
5
- options ||= {}
6
- options[:token] = token
7
- super(:Token, options)
8
- end
4
+ class Request
5
+ # TokenAuthentication is a middleware that adds a 'Token' header to a
6
+ # Faraday request.
7
+ class TokenAuthentication < load_middleware(:authorization)
8
+ # Public
9
+ def self.header(token, options = nil)
10
+ options ||= {}
11
+ options[:token] = token
12
+ super(:Token, options)
13
+ end
9
14
 
10
- def initialize(app, token, options = nil)
11
- super(app, token, options)
15
+ def initialize(app, token, options = nil)
16
+ super(app, token, options)
17
+ end
12
18
  end
13
19
  end
14
20
  end
15
-
@@ -1,36 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::UrlEncoded < Faraday::Middleware
3
- CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
4
+ class Request
5
+ # Middleware for supporting urlencoded requests.
6
+ class UrlEncoded < Faraday::Middleware
7
+ unless defined?(::Faraday::Request::UrlEncoded::CONTENT_TYPE)
8
+ CONTENT_TYPE = 'Content-Type'
9
+ end
4
10
 
5
- class << self
6
- attr_accessor :mime_type
7
- end
8
- self.mime_type = 'application/x-www-form-urlencoded'.freeze
11
+ class << self
12
+ attr_accessor :mime_type
13
+ end
14
+ self.mime_type = 'application/x-www-form-urlencoded'
9
15
 
10
- def call(env)
11
- match_content_type(env) do |data|
12
- params = Faraday::Utils::ParamsHash[data]
13
- env.body = params.to_query(env.params_encoder)
16
+ # Encodes as "application/x-www-form-urlencoded" if not already encoded or
17
+ # of another type.
18
+ #
19
+ # @param env [Faraday::Env]
20
+ def call(env)
21
+ match_content_type(env) do |data|
22
+ params = Faraday::Utils::ParamsHash[data]
23
+ env.body = params.to_query(env.params_encoder)
24
+ end
25
+ @app.call env
14
26
  end
15
- @app.call env
16
- end
17
27
 
18
- def match_content_type(env)
19
- if process_request?(env)
28
+ # @param env [Faraday::Env]
29
+ # @yield [request_body] Body of the request
30
+ def match_content_type(env)
31
+ return unless process_request?(env)
32
+
20
33
  env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
21
34
  yield(env.body) unless env.body.respond_to?(:to_str)
22
35
  end
23
- end
24
36
 
25
- def process_request?(env)
26
- type = request_type(env)
27
- env.body and (type.empty? or type == self.class.mime_type)
28
- end
37
+ # @param env [Faraday::Env]
38
+ #
39
+ # @return [Boolean] True if the request has a body and its Content-Type is
40
+ # urlencoded.
41
+ def process_request?(env)
42
+ type = request_type(env)
43
+ env.body && (type.empty? || (type == self.class.mime_type))
44
+ end
29
45
 
30
- def request_type(env)
31
- type = env.request_headers[CONTENT_TYPE].to_s
32
- type = type.split(';', 2).first if type.index(';')
33
- type
46
+ # @param env [Faraday::Env]
47
+ #
48
+ # @return [String]
49
+ def request_type(env)
50
+ type = env.request_headers[CONTENT_TYPE].to_s
51
+ type = type.split(';', 2).first if type.index(';')
52
+ type
53
+ end
34
54
  end
35
55
  end
36
56
  end