Note: introduced in 0.3.0
.
The Multipart Plugin provides a friendlier API to upload files using the multipart/form-data
) Content Type.
If you want to upload files, your server will more than probably expect them to be sent using the multipart/form-data
encoding. You can do that via the :form
parameter under a multipart
-enabled session:
path = "path/to/image.jpg"
# with pathnames
response = HTTPX.plugin(:multipart).post("https://example.com", form: {image: Pathname.new(path)})
# or with files
response = HTTPX.plugin(:multipart).post("https://example.com", form: {image: File.new(path)})
#
# ...
# Content-Type: multipart/form-data; boundary=---------------------a324a748aade297ac4ffc87108bee9ecd8cb2c2fea ...
# "-----------------------2a6965a264bbf67e519ad96cbc970800cac79dd240
# ...
# Content-Disposition: form-data; name="image"; filename="image.jpg"
# Content-Type: image/jpeg
#
# \xFF\xD8\xFF\xE0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xFF\xDB\x00\x84\x00\x02\x02\x02
If :form
gets passed string values, it’ll fallback to xxx-form-urlencoded
encoding:
response = HTTPX.plugin(:multipart).post("https://example.com", form: {foo: "bar"})
#
# ...
# foo=bar
In multipart payloads, the content type of String values will be set as “text/plain”.
For files, the type will be inferred using one of the following strategies:
filemagic
gem (if available);marcel
gem (if available);mime-magic
gem (if available);file
cli tool (if installed in the system);application/octet-stream
as fallback;HTTPX.plugin(:multipart).post("https://example.com", form: {image: Pathname.new(path)})
caveat: the integrations above are oriented towards media files which typically contain information about its first bytes, such as photos and videos, but may not work as well with text-based mime-types (such as “text/csv”).
You can override passing the file (or string) inside an hash with the following options:
HTTPX.plugin(:multipart).post("https://example.com", form: {
image: {
content_type: "image/png",
filename: "image.jpg",
body: Pathname.new("/path/to/file-xxx-yyy-zzz-random-data-uuid")
},
metadata: {
content_type: "application/json",
body: JSON.dump({ location: "Japan", frame_number: 2 })
}
})
you can also pass your own object responding to those fields as methods, and implementing #read(?Integer bytesize, ?String buffer)
:
class AwesomeVideo
def content_type
"video/mp4"
end
def filename
"gangnam-style.mp4"
end
def read(*)
.....
.....
end
# optionally, you can implement
# def close ; end
# and
# def rewind ; end
end
HTTPX.plugin(:multipart).post("https://example.com", form: {
video: AwesomeVideo.new
})
**(since v0.17
)
If your server responds with multipart content, it’s also possible to decode it:
require "httpx"
http = HTTPX.plugin(:multipart)
response = http.get("https://a.domain/responding-with-multipart")
parts = response.form
Parts are either plain strings (“text/plain” mime-type and the like), of “file parts”, object which immplement #original_filename
, #content_type
, and support the File API (#read
, etc…).
For versions older than 0.11.0
, you have to install the http-form_data
gem, in order to use this feature!
For 0.11.0
or later, httpx
still support HTTP::Part
or HTTP::File
values… however, you have to require the gem yourself.
This was an effort to ease the migration path whilst not breaking user code. But there were reasons not to rely on the gem, namely:
So consider migrating your multipart forms.
Next: Persistent