7

Here is the code which is working using Net::HTTP::Post

request = Net::HTTP::Post.new(url)
...
form_data = [
  ['attachments[]', File.open('file1.txt')],
  ['attachments[]', File.open('file2.txt')]
]
request.set_form form_data, 'multipart/form-data'
http.request(request)

Now, I am trying to use httparty like below but it is not working.

body = { attachments: [ File.open('file1.txt'), File.open('file2.txt') ] }

HTTParty.post(url, body: body)

The response I am getting from web service call is below:

#<HTTParty::Response:0x557d7b549f90 parsed_response={"error"=>true, "error_code"=>"invalid_attachment", "error_message"=>"Attachmen
t(s) not found or invalid."}, @response=#<Net::HTTPBadRequest 400 Bad Request readbody=true>, @headers={"server"=>["nginx"], "date"=>[
"Mon, 20 May 2019 07:41:50 GMT"], "content-type"=>["application/json"], "content-length"=>["102"], "connection"=>["close"], "vary"=>["
Authorization"], "set-cookie"=>["c18664e1c22ce71c0c91742fbeaaa863=uv425hihrbdatsql1udrlbs9as; path=/"], "expires"=>["Thu, 19 Nov 1981
08:52:00 GMT", "-1"], "cache-control"=>["no-store, no-cache, must-revalidate", "private, must-revalidate"], "pragma"=>["no-cache", "no
-cache"], "x-ratelimit-limit"=>["60"], "x-ratelimit-remaining"=>["59"], "strict-transport-security"=>["max-age=63072000; includeSubdom
ains;"]}>

It looks like it is not able to read the contents of files. Does HTTParty support this or I need to use some other gem?

Vasfed
  • 18,013
  • 10
  • 47
  • 53
Rajkaran Mishra
  • 4,532
  • 2
  • 36
  • 61

3 Answers3

0

Something like this should work, I just tested it, worked for me no problem.

HTTParty.post(url, 
              body: { attachments: [ 
                   File.read('foo.txt'), 
                   File.read('bar.txt')] })
lacostenycoder
  • 10,623
  • 4
  • 31
  • 48
0

With HTTParty you can pass IO/Files as parameters the same way (multipart is automatically set to true if there's a file in parameters).

But keep in mind that files should be closed after upload, otherwise you may run out of file descriptors before GC collects them:

files = ['file1.txt', 'file2.txt'].map{|fname| File.open(fname) }
begin
  HTTParty.post(url, body: { attachments: files })
ensure
  files.each(&:close)
end

That should work for you if net/http variant does (and is actually the same as your code).

Other thing to look at is content type detection by filename - because file upload consists of filename, content type and data itself. Error 400 with "invalid_attachment" you're getting suggests that more probably it's related to content type or other validation on server side (so make sure you're testing with the same files and nothing else changes other than http lib), also check httparty to be a recent version

Vasfed
  • 18,013
  • 10
  • 47
  • 53
0

I've written a test program which sends the same multipart request using both Net::HTTP and HTTParty. Then it compares and prints the request strings so that we can compare them. The only substantive difference between the two requests is that HTTParty attempts to guess and set the Content-Type header (e.g. text/plain for a file named file1.txt), whereas Net::HTTP always uses application/octet-stream.

HTTParty definitely does read the files and send them in the request. So, I suggest you investigate if the server is returning an error due to the Content-Type (maybe the content type in your particular request is not supported).

For your reference, here is the test program and specific results.

kgilpin
  • 2,201
  • 18
  • 18