Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Request and Response bodies #847

Merged
merged 4 commits into from Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions UPGRADING.md
Expand Up @@ -13,6 +13,10 @@ Please note `Faraday::ClientError` was previously used for both.
* Faraday::ProxyAuthError (407). Please note this raised a `Faraday::ConnectionFailed` before.
* Faraday::UnprocessableEntityError (422)

### Custom adapters
If you have written a custom adapter, please be aware that `env.body` is now an alias to the two new properties `request_body` and `response_body`.
This should work without you noticing if your adapter inherits from `Faraday::Adapter` and calls `save_response`, but if it doesn't, then please ensure you set the `status` BEFORE the `body` while processing the response.

### Others
* Dropped support for jruby and Rubinius.
* Officially supports Ruby 2.3+
Expand Down
18 changes: 16 additions & 2 deletions lib/faraday/options/env.rb
Expand Up @@ -43,9 +43,9 @@ module Faraday
#
# @!attribute reason_phrase
# @return [String]
class Env < Options.new(:method, :body, :url, :request, :request_headers,
class Env < Options.new(:method, :request_body, :url, :request, :request_headers,
:ssl, :parallel_manager, :params, :response, :response_headers, :status,
:reason_phrase)
:reason_phrase, :response_body)

ContentLength = 'Content-Length'.freeze
StatusesWithoutBody = Set.new [204, 304]
Expand Down Expand Up @@ -76,6 +76,7 @@ def self.from(value)

# @param key [Object]
def [](key)
return self[current_body] if key == :body
if in_member_set?(key)
super(key)
else
Expand All @@ -86,13 +87,26 @@ def [](key)
# @param key [Object]
# @param value [Object]
def []=(key, value)
return super(current_body, value) if key == :body
if in_member_set?(key)
super(key, value)
else
custom_members[key] = value
end
end

def current_body
!!status ? :response_body : :request_body
end

def body
self[:body]
end

def body=(value)
self[:body] = value
end

# @return [Boolean] true if status is in the set of {SuccessfulStatuses}.
def success?
SuccessfulStatuses.include?(status)
Expand Down
14 changes: 8 additions & 6 deletions lib/faraday/response.rb
Expand Up @@ -31,8 +31,6 @@ def initialize(env = nil)

attr_reader :env

def_delegators :env, :to_hash

def status
finished? ? env.status : nil
end
Expand Down Expand Up @@ -74,12 +72,16 @@ def success?
finished? && env.success?
end

def to_hash
{
:status => env.status, :body => env.body,
:response_headers => env.response_headers
}
end

# because @on_complete_callbacks cannot be marshalled
def marshal_dump
!finished? ? nil : {
:status => @env.status, :body => @env.body,
:response_headers => @env.response_headers
}
finished? ? to_hash : nil
end

def marshal_load(env)
Expand Down
59 changes: 45 additions & 14 deletions spec/faraday/options/env_spec.rb
@@ -1,21 +1,22 @@
RSpec.describe Faraday::Env do
subject { Faraday::Env.new }
subject(:env) { described_class.new }

it 'allows to access members' do
expect(subject.method).to be_nil
subject.method = :get
expect(subject.method).to eq(:get)
expect(env.method).to be_nil
env.method = :get
expect(env.method).to eq(:get)
end

it 'allows to access symbol non members' do
expect(subject[:custom]).to be_nil
subject[:custom] = :boom
expect(subject[:custom]).to eq(:boom)
expect(env[:custom]).to be_nil
env[:custom] = :boom
expect(env[:custom]).to eq(:boom)
end

it 'allows to access string non members' do
expect(subject['custom']).to be_nil
subject['custom'] = :boom
expect(subject['custom']).to eq(:boom)
expect(env['custom']).to be_nil
env['custom'] = :boom
expect(env['custom']).to eq(:boom)
end

it 'ignores false when fetching' do
Expand All @@ -25,13 +26,43 @@
end

it 'retains custom members' do
subject[:foo] = "custom 1"
subject[:bar] = :custom_2
env2 = Faraday::Env.from(subject)
env[:foo] = "custom 1"
env[:bar] = :custom_2
env2 = Faraday::Env.from(env)
env2[:baz] = "custom 3"

expect(env2[:foo]).to eq("custom 1")
expect(env2[:bar]).to eq(:custom_2)
expect(subject[:baz]).to be_nil
expect(env[:baz]).to be_nil
end

describe '#body' do
subject(:env) { described_class.from(body: { foo: 'bar' }) }

context 'when response is not finished yet' do
it 'returns the request body' do
expect(env.body).to eq({ foo: 'bar' })
end
end

context 'when response is finished' do
before do
env.status = 200
env.body = { bar: 'foo' }
env.response = Faraday::Response.new(env)
end

it 'returns the response body' do
expect(env.body).to eq({ bar: 'foo' })
end

it 'allows to access request_body' do
expect(env.request_body).to eq({ foo: 'bar' })
end

it 'allows to access response_body' do
expect(env.response_body).to eq({ bar: 'foo' })
end
end
end
end
1 change: 0 additions & 1 deletion spec/faraday/response_spec.rb
Expand Up @@ -25,7 +25,6 @@
let(:hash) { subject.to_hash }

it { expect(hash).to be_a(Hash) }
it { expect(hash).to eq(env.to_hash) }
it { expect(hash[:status]).to eq(subject.status) }
it { expect(hash[:response_headers]).to eq(subject.headers) }
it { expect(hash[:body]).to eq(subject.body) }
Expand Down
1 change: 0 additions & 1 deletion spec/support/shared_examples/request_method.rb
Expand Up @@ -167,7 +167,6 @@
it 'handles requests with proxy' do
conn_options[:proxy] = 'http://google.co.uk'

# binding.pry
res = conn.public_send(http_method, '/')
expect(res.status).to eq(200)
end
Expand Down