Overview
HTTParty is a popular Ruby gem for making HTTP requests. Multipart requests are essential for uploading files and submitting form data with mixed content types. HTTParty provides multiple approaches for handling multipart requests, from simple file uploads to complex form submissions.
Basic Multipart Request Syntax
The fundamental syntax for multipart requests in HTTParty uses the multipart: true
option:
require 'httparty'
response = HTTParty.post(
'https://api.example.com/upload',
body: {
field1: 'value1',
file: File.open('document.pdf')
},
multipart: true
)
Simple File Upload
The most straightforward approach for uploading a single file:
require 'httparty'
# Upload a single file with form data
response = HTTParty.post(
'https://httpbin.org/post',
body: {
'description' => 'My uploaded file',
'category' => 'documents',
'file' => File.open('example.pdf', 'rb')
},
multipart: true
)
puts response.code
puts response.body
Multiple File Upload
To upload multiple files in a single request:
require 'httparty'
files = [
File.open('document1.pdf', 'rb'),
File.open('image.jpg', 'rb'),
File.open('data.csv', 'rb')
]
response = HTTParty.post(
'https://api.example.com/upload',
body: {
'project_name' => 'My Project',
'files' => files
},
multipart: true
)
# Don't forget to close the files
files.each(&:close)
Advanced Multipart with MIME Types
For more control over file uploads, you can specify MIME types explicitly:
require 'httparty'
require 'mime/types'
# Determine MIME type automatically
file_path = 'example.png'
mime_type = MIME::Types.type_for(file_path).first&.content_type || 'application/octet-stream'
file = File.open(file_path, 'rb')
body = {
'title' => 'Image Upload',
'tags' => 'photo,example',
'image' => HTTParty::Request::Multipart::File.new(file, mime_type, File.basename(file_path))
}
response = HTTParty.post(
'https://api.example.com/images',
body: body,
multipart: true
)
file.close
Multipart with Custom Headers
You can add custom headers to multipart requests:
require 'httparty'
response = HTTParty.post(
'https://api.example.com/upload',
body: {
'metadata' => '{"version": "1.0"}',
'file' => File.open('data.json', 'rb')
},
headers: {
'Authorization' => 'Bearer your-token-here',
'X-Custom-Header' => 'custom-value'
},
multipart: true
)
Working with StringIO
For uploading content that's not stored as files:
require 'httparty'
require 'stringio'
# Create content in memory
csv_content = "name,email\nJohn,john@example.com\nJane,jane@example.com"
csv_io = StringIO.new(csv_content)
response = HTTParty.post(
'https://api.example.com/import',
body: {
'format' => 'csv',
'data' => HTTParty::Request::Multipart::File.new(csv_io, 'text/csv', 'data.csv')
},
multipart: true
)
Error Handling
Always include proper error handling for multipart requests:
require 'httparty'
begin
file = File.open('large-file.zip', 'rb')
response = HTTParty.post(
'https://api.example.com/upload',
body: {
'file' => file,
'checksum' => Digest::MD5.hexdigest(file.read)
},
multipart: true,
timeout: 300 # 5 minutes for large files
)
if response.success?
puts "Upload successful: #{response.parsed_response}"
else
puts "Upload failed: #{response.code} - #{response.message}"
end
rescue HTTParty::Error => e
puts "HTTParty error: #{e.message}"
rescue StandardError => e
puts "General error: #{e.message}"
ensure
file&.close
end
Key Points to Remember
- Automatic Headers: HTTParty automatically sets the
Content-Type
header tomultipart/form-data
whenmultipart: true
is used - File Handling: Always close file handles after use to prevent resource leaks
- MIME Types: HTTParty can auto-detect MIME types, but you can specify them explicitly for better control
- Timeouts: Consider setting longer timeouts for large file uploads
- Error Handling: Always implement proper error handling for network operations
Installation
Ensure you have HTTParty installed:
gem install httparty
# Or add to your Gemfile
gem 'httparty'
For MIME type detection, also install:
gem install mime-types