Multipart queries are used quite a lot in the transfer of data around the Internet. There are a number of projects out there that will generate multipart content such as email libraries and even web frameworks for uploading and working with files. When we came create parts of CloudMailin we couldn’t find a gem that would easily allow us to encode multipart content the way we wanted to. We could have used a library that already this ability it baked in but most of them didn’t work with eventmachine and if they did then we couldn’t be sure that they would work with any testing tools that we created later that didn’t rely on eventmachine. Although loads of libraries were implementing this code we couldn’t find anything that was standalone that we could just use across any of the different libraries that could post content.
In order to solve this issue we created our own internal multipart creation code. This weekend we have released that code as a gem called multipart_body. This gem is far from perfect and we have a list of things that we don’t have time to add and we would love some help with but the code has been useful to us so we hope it will be useful to others too.
The gem itself consits of two parts. Multipart body and the parts. To get started just install the gem
$ gem install multipart_body
Once the gem is installed you can create a form-data multipart body using this quick hash shorthand.
multipart = Multipart.new(:field1 => 'content', :field2 => 'something else')
To get a little more control you can create the parts yourself and use them to create the body:
# using a hash
part = Part.new(:name => 'name', :body => 'body', :filename => 'f.txt', :content_type => 'text/plain')
# or just with the name, body and an optional filename
part = Part.new('name', 'content', 'file.txt')
multipart = Multipart.new([part])
You can also pass a file to the multipart hash to automatically assign the filename:
multipart = Multipart.new(:field1 => 'content', :field2 => File.new('test.txt'))
The resulting output can then be created as follows:
part.to_s #=> The part with headers and content
multipart.to_s #=> The full list of parts joined by boundaries
So the following code example will create the output that follows:
multipart = MultipartBody.new(:test => 'content', :myfile => File.new('test.txt'))
Content-Disposition: form-data; name="myfile"; filename="test.txt"
Content-Disposition: form-data; name="test"
Like I said before the gem is far from perfect. At the moment it doesn’t have any documentation and it is missing quite a few features. By default it assumes you are creating form-data content and encodings are completely missing at the moment.
Hopefully though with a little bit of help it can provide a great starting block for anyone wishing to implement multipart bodies so that each library doesn’t have to re-invent this. If anyone has any time I’d love to see patches to bring this up to something much more useful.