From ee5d658f8b2d0fa203a6868c4e0f9cb322236cf9 Mon Sep 17 00:00:00 2001 From: Jeremy ISRAEL Date: Thu, 29 Aug 2019 18:53:57 +0200 Subject: [PATCH] Allow JSON and IO in the same payload --- lib/faraday/request/multipart.rb | 17 ++++++++++- spec/faraday/request/multipart_spec.rb | 39 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/faraday/request/multipart.rb b/lib/faraday/request/multipart.rb index 09aa6c610..02ad2917d 100644 --- a/lib/faraday/request/multipart.rb +++ b/lib/faraday/request/multipart.rb @@ -52,7 +52,7 @@ def has_multipart?(obj) # rubocop:disable Naming/PredicateName def create_multipart(env, params) boundary = env.request.boundary parts = process_params(params) do |key, value| - Faraday::Parts::Part.new(boundary, key, value) + part(boundary, key, value) end parts << Faraday::Parts::EpiloguePart.new(boundary) @@ -61,6 +61,21 @@ def create_multipart(env, params) body end + def part(boundary, key, value) + if json?(value) + header = { 'Content-Type' => 'application/json' } + Faraday::Parts::Part.new(boundary, key, value, header) + else + Faraday::Parts::Part.new(boundary, key, value) + end + end + + def json?(value) + JSON.parse(value) + rescue StandardError + false + end + # @return [String] def unique_boundary "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}" diff --git a/spec/faraday/request/multipart_spec.rb b/spec/faraday/request/multipart_spec.rb index 3f8979eb0..ccea4ebdb 100644 --- a/spec/faraday/request/multipart_spec.rb +++ b/spec/faraday/request/multipart_spec.rb @@ -68,6 +68,45 @@ end end + context 'when providing json and IO content in the same payload' do + let(:io_content) { StringIO.new('io-content') } + let(:json_content) do + { + b: 1, + c: 2 + }.to_json + end + + let(:payload) do + { + json_content: json_content, + io_content: Faraday::UploadIO.new(io_content, 'application/pdf') + } + end + + it_behaves_like 'a multipart request' + + it 'forms a multipart request' do + response = conn.post('/echo', payload) + + boundary = parse_multipart_boundary(response.headers['Content-Type']) + result = parse_multipart(boundary, response.body) + expect(result[:errors]).to be_empty + + part_json, body_json = result.part('json_content') + expect(part_json).to_not be_nil + expect(part_json.mime).to eq('application/json') + expect(part_json.filename).to be_nil + expect(body_json).to eq(json_content) + + part_io, body_io = result.part('io_content') + expect(part_io).to_not be_nil + expect(part_io.mime).to eq('application/pdf') + expect(part_io.filename).to eq('local.path') + expect(body_io).to eq(io_content.string) + end + end + context 'when multipart objects in array param' do let(:payload) do {