Ruby Multipart Post/Put Request
Monday Oct 19, 2009
I had to modify a client app to perform a multipart PUT request and ran into a few snags that I'd like to share. The first is that there isn't a single common way to do this in Ruby. Ruby has a Net::HTTP API but it operates at a primitive level and so a higher level API would be useful. I like using the RestClient gem, but the mainline version does not support multipart POST/PUT requests yet. There is a @technoweenie fork of the gem that does, however, it is based on an older version. The app I was modifying was not based on this fork which is missing some useful features such as logging. Enter @nickseiger's multipart-post gem which does just what I need. This gem provides some code that works with Net::HTTP and supports both mutlipart POST and PUT requests. However, it also requires working with Net::HTTP directly which isn't as easy to use as RestClient.
One problem I ran into was that Net::HTTP does not automatically detect the use of TLS/SSL and so you must explicitly tell it to use it. I found some other posts like this one. Basically, one needs to set the instance attribute Net::HTTP#use_ssl separately. My version of the code is below. This is part of a larger example on using the Kenai APIs which can be found within the kenaiapis examples repository.
class KenaiClient
# Code that uses rest-client gem
@host = "https://kenai.com"
...
module MultipartClient
require 'net/http/post/multipart'
def wiki_image_client(project, image_filename)
@url = URI.parse("#{@host}/api/projects/#{project}/features/wiki/images/#{image_filename}")
@initial_headers = { "accept" => 'application/json' }
self
end
def put(payload, additional_headers = {})
req = Net::HTTP::Put::Multipart.new(@url.path, payload, @initial_headers.merge(additional_headers))
req.basic_auth(@user, @password)
http = Net::HTTP.new(@url.host, @url.port)
if @url.port == 443
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
unless @warning_printed
puts "\nwarning: peer certificate for #{@url.host} won't be verified"
@warning_printed = true
end
end
res = http.start do |http|
http.request(req)
end
raise "Request failed with response: #{res}" unless Net::HTTPSuccess === res
end
end
include MultipartClient
end










