Deep Tech Point
first stop in your tech adventure
Send file via REST API
January 31, 2021 | Javascript

What if you are developing an application that requires a client to upload a file or an image and information about the image via RESTful API and you want the client to send data as JSON? The easy answer would be to perform two posts to REST API.
But is that even possible in a single request?

Again, a quick answer would be to send Base64 encoded file data in a JSON string.
However, in reality, you have several different options:

If you decide to use Base64 encoding useful functions are btoa() and atob(). The first one, btoa(), is the acronym of Binary to ASCII and is used for encoding binary data to ASCII representation. The second one, atob(), the acronym of ASCII to Binary, will decode ASCII encoded binary string to its original binary representation.
The example could be something like this:

<input type="file" id="filePicker">

<script>
var handleFileSelect = function(evt) {
    var files = evt.target.files;
    var file = files[0];

    if (files && file) {
        var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var base64String = btoa(readerEvt.target.result);
            // add base64String encoded file to your JSON API request
        };

        reader.readAsBinaryString(file);
    }
};

if (window.File && window.FileReader && window.FileList && window.Blob) {
    document.getElementById('filePicker').addEventListener('change', handleFileSelect, false);
} else {
    alert('The File APIs are not fully supported in this browser.');
}
</script>

I won’t dive into details regarding the second option and third option since these involve two requests one for JSON information and one for file, which is pretty straightforward. The only difference between these two is the sequence of requests.

The final option is sending multipart/related content type for multiple objects in one package. In our case, these are JSON and file objects. It would look like this:

POST /api_endpoint HTTP/1.1
Content-Type: multipart/related; boundary=PART
--PART
Content-Type: application/json

{
   "someKey": "someValue"
}
--PART
Content-Type: image/jpeg
Content-Length: 435029
Content-Transfer-Encoding: binary

[DATA (435029 bytes)]
--PART

Keep in mind that .send() method of XMLHttpRequest encodes data into UTF-8. To avoid this you can convert data to an array and send it as ArrayBuffer, or you could use .sendAsBinary() method.