faraday 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +3 -4
- data/examples/client_spec.rb +1 -1
- data/lib/faraday/adapter/em_http.rb +3 -2
- data/lib/faraday/adapter/excon.rb +2 -2
- data/lib/faraday/adapter/httpclient.rb +2 -1
- data/lib/faraday/adapter/net_http.rb +18 -8
- data/lib/faraday/adapter/typhoeus.rb +1 -1
- data/lib/faraday/adapter.rb +1 -0
- data/lib/faraday/adapter_registry.rb +3 -1
- data/lib/faraday/autoload.rb +1 -1
- data/lib/faraday/connection.rb +3 -3
- data/lib/faraday/dependency_loader.rb +3 -1
- data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
- data/lib/faraday/encoders/nested_params_encoder.rb +7 -2
- data/lib/faraday/error.rb +8 -0
- data/lib/faraday/options.rb +4 -8
- data/lib/faraday/rack_builder.rb +13 -12
- data/lib/faraday/request/authorization.rb +3 -1
- data/lib/faraday/request/multipart.rb +10 -3
- data/lib/faraday/request/url_encoded.rb +3 -1
- data/lib/faraday/request.rb +20 -10
- data/lib/faraday/response/raise_error.rb +12 -1
- data/lib/faraday/response.rb +4 -1
- data/lib/faraday/utils/headers.rb +2 -2
- data/lib/faraday/utils.rb +11 -3
- data/lib/faraday.rb +2 -2
- data/spec/faraday/adapter/em_http_spec.rb +1 -1
- data/spec/faraday/adapter/em_synchrony_spec.rb +1 -1
- data/spec/faraday/adapter/patron_spec.rb +1 -1
- data/spec/faraday/adapter/test_spec.rb +260 -0
- data/spec/faraday/params_encoders/flat_spec.rb +8 -0
- data/spec/faraday/params_encoders/nested_spec.rb +8 -0
- data/spec/faraday/rack_builder_spec.rb +150 -1
- data/spec/faraday/request/authorization_spec.rb +2 -2
- data/spec/faraday/request/multipart_spec.rb +41 -13
- data/spec/faraday/request/url_encoded_spec.rb +13 -0
- data/spec/faraday/request_spec.rb +16 -5
- data/spec/faraday/response/middleware_spec.rb +16 -0
- data/spec/faraday/response/raise_error_spec.rb +33 -0
- data/spec/support/shared_examples/request_method.rb +3 -3
- metadata +21 -6
- data/UPGRADING.md +0 -55
@@ -4,7 +4,9 @@ module Faraday
|
|
4
4
|
class Request
|
5
5
|
# Middleware for supporting urlencoded requests.
|
6
6
|
class UrlEncoded < Faraday::Middleware
|
7
|
-
|
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
|
data/lib/faraday/request.rb
CHANGED
@@ -12,7 +12,7 @@ module Faraday
|
|
12
12
|
# req.body = 'abc'
|
13
13
|
# end
|
14
14
|
#
|
15
|
-
# @!attribute
|
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
|
@@ -26,7 +26,9 @@ module Faraday
|
|
26
26
|
# @return [RequestOptions] options
|
27
27
|
#
|
28
28
|
# rubocop:disable Style/StructInheritance
|
29
|
-
class Request < Struct.new(
|
29
|
+
class Request < Struct.new(
|
30
|
+
:http_method, :path, :params, :headers, :body, :options
|
31
|
+
)
|
30
32
|
# rubocop:enable Style/StructInheritance
|
31
33
|
|
32
34
|
extend MiddlewareRegistry
|
@@ -56,6 +58,14 @@ module Faraday
|
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
61
|
+
def method
|
62
|
+
warn <<~TEXT
|
63
|
+
WARNING: `Faraday::Request##{__method__}` is deprecated; use `#http_method` instead. It will be removed in or after version 2.0.
|
64
|
+
`Faraday::Request##{__method__}` called from #{caller_locations(1..1).first}
|
65
|
+
TEXT
|
66
|
+
http_method
|
67
|
+
end
|
68
|
+
|
59
69
|
# Replace params, preserving the existing hash type.
|
60
70
|
#
|
61
71
|
# @param hash [Hash] new params
|
@@ -116,7 +126,7 @@ module Faraday
|
|
116
126
|
# @return [Hash] the hash ready to be serialized in Marshal.
|
117
127
|
def marshal_dump
|
118
128
|
{
|
119
|
-
|
129
|
+
http_method: http_method,
|
120
130
|
body: body,
|
121
131
|
headers: headers,
|
122
132
|
path: path,
|
@@ -129,17 +139,17 @@ module Faraday
|
|
129
139
|
# Restores the instance variables according to the +serialised+.
|
130
140
|
# @param serialised [Hash] the serialised object.
|
131
141
|
def marshal_load(serialised)
|
132
|
-
self.
|
133
|
-
self.body
|
134
|
-
self.headers
|
135
|
-
self.path
|
136
|
-
self.params
|
137
|
-
self.options
|
142
|
+
self.http_method = serialised[:http_method]
|
143
|
+
self.body = serialised[:body]
|
144
|
+
self.headers = serialised[:headers]
|
145
|
+
self.path = serialised[:path]
|
146
|
+
self.params = serialised[:params]
|
147
|
+
self.options = serialised[:options]
|
138
148
|
end
|
139
149
|
|
140
150
|
# @return [Env] the Env for this Request
|
141
151
|
def to_env(connection)
|
142
|
-
Env.new(
|
152
|
+
Env.new(http_method, body, connection.build_exclusive_url(path, params),
|
143
153
|
options, headers, connection.ssl, connection.parallel_manager)
|
144
154
|
end
|
145
155
|
end
|
@@ -38,7 +38,18 @@ module Faraday
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def response_values(env)
|
41
|
-
{
|
41
|
+
{
|
42
|
+
status: env.status,
|
43
|
+
headers: env.response_headers,
|
44
|
+
body: env.body,
|
45
|
+
request: {
|
46
|
+
method: env.method,
|
47
|
+
url_path: env.url.path,
|
48
|
+
params: env.params,
|
49
|
+
headers: env.request_headers,
|
50
|
+
body: env.request_body
|
51
|
+
}
|
52
|
+
}
|
42
53
|
end
|
43
54
|
end
|
44
55
|
end
|
data/lib/faraday/response.rb
CHANGED
@@ -15,8 +15,11 @@ module Faraday
|
|
15
15
|
|
16
16
|
# Override this to modify the environment after the response has finished.
|
17
17
|
# Calls the `parse` method if defined
|
18
|
+
# `parse` method can be defined as private, public and protected
|
18
19
|
def on_complete(env)
|
19
|
-
|
20
|
+
return unless respond_to?(:parse, true) && env.parse_body?
|
21
|
+
|
22
|
+
env.body = parse(env.body)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
@@ -105,7 +105,7 @@ module Faraday
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def to_hash
|
108
|
-
|
108
|
+
{}.update(self)
|
109
109
|
end
|
110
110
|
|
111
111
|
def parse(header_string)
|
@@ -114,7 +114,7 @@ module Faraday
|
|
114
114
|
headers = header_string.split(/\r\n/)
|
115
115
|
|
116
116
|
# Find the last set of response headers.
|
117
|
-
start_index = headers.rindex { |x| x.
|
117
|
+
start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0
|
118
118
|
last_response = headers.slice(start_index, headers.size)
|
119
119
|
|
120
120
|
last_response
|
data/lib/faraday/utils.rb
CHANGED
@@ -16,12 +16,20 @@ module Faraday
|
|
16
16
|
NestedParamsEncoder.encode(params)
|
17
17
|
end
|
18
18
|
|
19
|
+
def default_space_encoding
|
20
|
+
@default_space_encoding ||= '+'
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_writer :default_space_encoding
|
25
|
+
end
|
26
|
+
|
19
27
|
ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
|
20
28
|
|
21
29
|
def escape(str)
|
22
30
|
str.to_s.gsub(ESCAPE_RE) do |match|
|
23
|
-
|
24
|
-
end.
|
31
|
+
"%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
|
32
|
+
end.gsub(' ', default_space_encoding)
|
25
33
|
end
|
26
34
|
|
27
35
|
def unescape(str)
|
@@ -81,7 +89,7 @@ module Faraday
|
|
81
89
|
# the path with the query string sorted.
|
82
90
|
def normalize_path(url)
|
83
91
|
url = URI(url)
|
84
|
-
(url.path.start_with?('/') ? url.path :
|
92
|
+
(url.path.start_with?('/') ? url.path : "/#{url.path}") +
|
85
93
|
(url.query ? "?#{sort_query_params(url.query)}" : '')
|
86
94
|
end
|
87
95
|
|
data/lib/faraday.rb
CHANGED
@@ -19,7 +19,7 @@ require 'faraday/dependency_loader'
|
|
19
19
|
# conn.get '/'
|
20
20
|
#
|
21
21
|
module Faraday
|
22
|
-
VERSION = '1.
|
22
|
+
VERSION = '1.1.0'
|
23
23
|
METHODS_WITH_QUERY = %w[get head delete trace].freeze
|
24
24
|
METHODS_WITH_BODY = %w[post put patch].freeze
|
25
25
|
|
@@ -153,7 +153,7 @@ module Faraday
|
|
153
153
|
@default_connection_options = ConnectionOptions.from(options)
|
154
154
|
end
|
155
155
|
|
156
|
-
unless
|
156
|
+
unless defined?(::Faraday::Timer)
|
157
157
|
require 'timeout'
|
158
158
|
Timer = Timeout
|
159
159
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe Faraday::Adapter::EMHttp do
|
3
|
+
RSpec.describe Faraday::Adapter::EMHttp, unless: defined?(JRUBY_VERSION) do
|
4
4
|
features :request_body_on_query_methods, :reason_phrase_parse, :trace_method,
|
5
5
|
:skip_response_body_on_head, :parallel, :local_socket_binding
|
6
6
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe Faraday::Adapter::EMSynchrony do
|
3
|
+
RSpec.describe Faraday::Adapter::EMSynchrony, unless: defined?(JRUBY_VERSION) do
|
4
4
|
features :request_body_on_query_methods, :reason_phrase_parse,
|
5
5
|
:skip_response_body_on_head, :parallel, :local_socket_binding
|
6
6
|
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Adapter::Test do
|
4
|
+
let(:stubs) do
|
5
|
+
described_class::Stubs.new do |stub|
|
6
|
+
stub.get('http://domain.test/hello') do
|
7
|
+
[200, { 'Content-Type' => 'text/html' }, 'domain: hello']
|
8
|
+
end
|
9
|
+
|
10
|
+
stub.get('http://wrong.test/hello') do
|
11
|
+
[200, { 'Content-Type' => 'text/html' }, 'wrong: hello']
|
12
|
+
end
|
13
|
+
|
14
|
+
stub.get('http://wrong.test/bait') do
|
15
|
+
[404, { 'Content-Type' => 'text/html' }]
|
16
|
+
end
|
17
|
+
|
18
|
+
stub.get('/hello') do
|
19
|
+
[200, { 'Content-Type' => 'text/html' }, 'hello']
|
20
|
+
end
|
21
|
+
|
22
|
+
stub.get('/method-echo') do |env|
|
23
|
+
[200, { 'Content-Type' => 'text/html' }, env[:method].to_s]
|
24
|
+
end
|
25
|
+
|
26
|
+
stub.get(%r{\A/resources/\d+(?:\?|\z)}) do
|
27
|
+
[200, { 'Content-Type' => 'text/html' }, 'show']
|
28
|
+
end
|
29
|
+
|
30
|
+
stub.get(%r{\A/resources/(specified)\z}) do |_env, meta|
|
31
|
+
[200, { 'Content-Type' => 'text/html' }, "show #{meta[:match_data][1]}"]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:connection) do
|
37
|
+
Faraday.new do |builder|
|
38
|
+
builder.adapter :test, stubs
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:response) { connection.get('/hello') }
|
43
|
+
|
44
|
+
context 'with simple path sets status' do
|
45
|
+
subject { response.status }
|
46
|
+
|
47
|
+
it { is_expected.to eq 200 }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with simple path sets headers' do
|
51
|
+
subject { response.headers['Content-Type'] }
|
52
|
+
|
53
|
+
it { is_expected.to eq 'text/html' }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with simple path sets body' do
|
57
|
+
subject { response.body }
|
58
|
+
|
59
|
+
it { is_expected.to eq 'hello' }
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'with host points to the right stub' do
|
63
|
+
subject { connection.get('http://domain.test/hello').body }
|
64
|
+
|
65
|
+
it { is_expected.to eq 'domain: hello' }
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'can be called several times' do
|
69
|
+
subject { connection.get('/hello').body }
|
70
|
+
|
71
|
+
it { is_expected.to eq 'hello' }
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'can handle regular expression path' do
|
75
|
+
subject { connection.get('/resources/1').body }
|
76
|
+
|
77
|
+
it { is_expected.to eq 'show' }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'can handle single parameter block' do
|
81
|
+
subject { connection.get('/method-echo').body }
|
82
|
+
|
83
|
+
it { is_expected.to eq 'get' }
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'can handle regular expression path with captured result' do
|
87
|
+
subject { connection.get('/resources/specified').body }
|
88
|
+
|
89
|
+
it { is_expected.to eq 'show specified' }
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with get params' do
|
93
|
+
subject { connection.get('/param?a=1').body }
|
94
|
+
|
95
|
+
before do
|
96
|
+
stubs.get('/param?a=1') { [200, {}, 'a'] }
|
97
|
+
end
|
98
|
+
|
99
|
+
it { is_expected.to eq 'a' }
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'ignoring unspecified get params' do
|
103
|
+
before do
|
104
|
+
stubs.get('/optional?a=1') { [200, {}, 'a'] }
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with multiple params' do
|
108
|
+
subject { connection.get('/optional?a=1&b=1').body }
|
109
|
+
|
110
|
+
it { is_expected.to eq 'a' }
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'with single param' do
|
114
|
+
subject { connection.get('/optional?a=1').body }
|
115
|
+
|
116
|
+
it { is_expected.to eq 'a' }
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'without params' do
|
120
|
+
subject(:request) { connection.get('/optional') }
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect { request }.to raise_error(
|
124
|
+
Faraday::Adapter::Test::Stubs::NotFound
|
125
|
+
)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'with http headers' do
|
131
|
+
before do
|
132
|
+
stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
|
133
|
+
stubs.get('/yo') { [200, {}, 'b'] }
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'with header' do
|
137
|
+
subject do
|
138
|
+
connection.get('/yo') { |env| env.headers['X-HELLO'] = 'hello' }.body
|
139
|
+
end
|
140
|
+
|
141
|
+
it { is_expected.to eq 'a' }
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'without header' do
|
145
|
+
subject do
|
146
|
+
connection.get('/yo').body
|
147
|
+
end
|
148
|
+
|
149
|
+
it { is_expected.to eq 'b' }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'different outcomes for the same request' do
|
154
|
+
def make_request
|
155
|
+
connection.get('/foo')
|
156
|
+
end
|
157
|
+
|
158
|
+
subject(:request) { make_request.body }
|
159
|
+
|
160
|
+
before do
|
161
|
+
stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
|
162
|
+
stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'world'] }
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'the first request' do
|
166
|
+
it { is_expected.to eq 'hello' }
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'the second request' do
|
170
|
+
before do
|
171
|
+
make_request
|
172
|
+
end
|
173
|
+
|
174
|
+
it { is_expected.to eq 'world' }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe 'yielding env to stubs' do
|
179
|
+
subject { connection.get('http://foo.com/foo?a=1').body }
|
180
|
+
|
181
|
+
before do
|
182
|
+
stubs.get '/foo' do |env|
|
183
|
+
expect(env[:url].path).to eq '/foo'
|
184
|
+
expect(env[:url].host).to eq 'foo.com'
|
185
|
+
expect(env[:params]['a']).to eq '1'
|
186
|
+
expect(env[:request_headers]['Accept']).to eq 'text/plain'
|
187
|
+
[200, {}, 'a']
|
188
|
+
end
|
189
|
+
|
190
|
+
connection.headers['Accept'] = 'text/plain'
|
191
|
+
end
|
192
|
+
|
193
|
+
it { is_expected.to eq 'a' }
|
194
|
+
end
|
195
|
+
|
196
|
+
describe 'params parsing' do
|
197
|
+
subject { connection.get('http://foo.com/foo?a[b]=1').body }
|
198
|
+
|
199
|
+
context 'with default encoder' do
|
200
|
+
before do
|
201
|
+
stubs.get '/foo' do |env|
|
202
|
+
expect(env[:params]['a']['b']).to eq '1'
|
203
|
+
[200, {}, 'a']
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
it { is_expected.to eq 'a' }
|
208
|
+
end
|
209
|
+
|
210
|
+
context 'with nested encoder' do
|
211
|
+
before do
|
212
|
+
stubs.get '/foo' do |env|
|
213
|
+
expect(env[:params]['a']['b']).to eq '1'
|
214
|
+
[200, {}, 'a']
|
215
|
+
end
|
216
|
+
|
217
|
+
connection.options.params_encoder = Faraday::NestedParamsEncoder
|
218
|
+
end
|
219
|
+
|
220
|
+
it { is_expected.to eq 'a' }
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'with flat encoder' do
|
224
|
+
before do
|
225
|
+
stubs.get '/foo' do |env|
|
226
|
+
expect(env[:params]['a[b]']).to eq '1'
|
227
|
+
[200, {}, 'a']
|
228
|
+
end
|
229
|
+
|
230
|
+
connection.options.params_encoder = Faraday::FlatParamsEncoder
|
231
|
+
end
|
232
|
+
|
233
|
+
it { is_expected.to eq 'a' }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe 'raising an error if no stub was found' do
|
238
|
+
describe 'for request' do
|
239
|
+
subject(:request) { connection.get('/invalid') { [200, {}, []] } }
|
240
|
+
|
241
|
+
it { expect { request }.to raise_error described_class::Stubs::NotFound }
|
242
|
+
end
|
243
|
+
|
244
|
+
describe 'for specified host' do
|
245
|
+
subject(:request) { connection.get('http://domain.test/bait') }
|
246
|
+
|
247
|
+
it { expect { request }.to raise_error described_class::Stubs::NotFound }
|
248
|
+
end
|
249
|
+
|
250
|
+
describe 'for request without specified header' do
|
251
|
+
subject(:request) { connection.get('/yo') }
|
252
|
+
|
253
|
+
before do
|
254
|
+
stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
|
255
|
+
end
|
256
|
+
|
257
|
+
it { expect { request }.to raise_error described_class::Stubs::NotFound }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|