When trying to POST multipart data (file & json) with Faraday gem, remote server is not recognizing json data parameter and failing with validation error as it is required parameter.
connection = Faraday.new(url: "#{uri.scheme}://#{uri.host}:#{uri.port}") do |faraday|
faraday.request :multipart
faraday.request :url_encoded
faraday.adapter :net_http
end
request_data = { file: Faraday::UploadIO.new('somefile.png', 'image/png'), jsonBody: JSON.dump({ id: 'foo', name: 'bar' }) }
response = connection.post(uri.request_uri) do |request|
request = Ff::Api::RequestHeaders.set(request, self.api_options)
request.headers['content-type'] = 'multipart/form-data; boundary=-----------RubyMultipartPost'
request.body = request_data
end
Working CURL request:
curl -v -H 'Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1' \
-H 'Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain' \
-H 'Content-Type: multipart/form-data' \
-F 'jsonBody={"id":"foo","name":"bar"};type=application/json' \
'http://localhost:8080/localproject/rest-resource/items'
Curl Log:
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /localproject/rest-resource/items HTTP/1.1
> Host: localhost:8080
> Authorization: bearer 7d70fb31-0eb9-4846-9ea8-933dfb69d8f1
> USER_IP_ADDR: 127.0.0.1
> Accept: application/xml,application/xhtml+xml,application/json,text/html,text/plain
> Content-Length: 555
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------0c5f3acb5a4731ff
>
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Thu, 08 Feb 2018 10:50:06 GMT
<
* Connection #0 to host localhost left intact
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><updateResponse><id>5ce0b335-4638-474c-8c4a-9adb6c54b057</id><success>true</success></updateResponse>%
Additional prefix "type=application/json" to request body seems to be making difference with CURL. Did not find any way to do the same with Faraday.
Faraday Version: 0.12.2 & 0.14.0
Ruby Version: 2.3.3
Rails: 5.2
Any help will be greatly appreciated.
Found that Faraday doesn't support mix multipart request (file upload with json/xml data). This is because mixing file and json data is not restful approach and should be avoided entirely. More discussion is happening here https://github.com/lostisland/faraday/issues/769
I have temporarily fixed the issue by patching Faraday::Mulitipart
class to allow mixing JSON data,
class Faraday::Request::Multipart
def create_multipart(env, params)
boundary = env.request.boundary
parts = process_params(params) do |key, value|
if (JSON.parse(value) rescue false)
Faraday::Parts::Part.new(boundary, key, value, 'Content-Type' => 'application/json')
else
Faraday::Parts::Part.new(boundary, key, value)
end
end
parts << Faraday::Parts::EpiloguePart.new(boundary)
body = Faraday::CompositeReadIO.new(parts)
env.request_headers[Faraday::Env::ContentLength] = body.length.to_s
return body
end
end
But in long term one should change server implementation to avoid mix multipart requests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With