Search code examples
javascriptfetch-apimime-types

Does having `content-type: application/octet-stream` necessarily means that we should set request body as a binary form?


I have this sample request with cUrl in the contract (the contract docs only show this for the endpoints):

curl \
    -X PUT \
    -H 'Content-Type: application/octet-stream' \
    -H 'Content-Disposition: attachment; filename=file.pdf \
    --upload-file my-file \
    https://storage.google.apis.com/…..

The endpoints intended to update an image. I have only an image in the base64 string format, and I want to upload this data through this endpoint.

  1. Since the API docs only provide that information, should I directly pass the base64 string as the request body as below:
const dummyBase64Image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABjElEQVRIS+2VvUoDQRSGv9V2'

fetch(
    'https://storage.google.apis.com/…',
    {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/octet-stream',
            'Content-Disposition': 'attachment; filename="dummy.js"'
        },
        body: dummyBase64Image,
    }
)..... // callback handling

Or should I parse the image with the base64 string format into another form (such as parse the base64 string into binary format)?

  1. Is the request sample with cUrl and content-type: application/octet-stream in the documentation enough to conclude that the request body form must be mere a base64 string format (fetch chaining shown above)and not like the usual object that is being passed in the request body with some predetermined field name such as (below fetch chaining):
fetch(
    'https://storage.google.apis.com/…',
    {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/octet-stream',
            'Content-Disposition': 'attachment; filename="dummy.js"',
        },
        body: {
            image: dummyBase64Image,
        }
    }
)..... // callback handling

Solution

  • Yes, you need to convert from base64 format to raw binary format, in a Blob or Buffer, keep in mind that you need to remove the data:image/[extension];base64, because it is just a prefix is used to identify the content in a data URI scheme.

    const dummyBase64Image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABjElEQVRIS+2VvUoDQRSGv9V2';
    
    
    function base64ToBlob(base64, mimeType) {
        const byteCharacters = atob(base64.replace(/^data:image\/(png|jpeg|jpg);base64,/, ''));
        const byteArrays = [];
    
        for (let offset = 0; offset < byteCharacters.length; offset += 512) {
            const slice = byteCharacters.slice(offset, offset + 512);
            const byteNumbers = new Array(slice.length);
            for (let i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }
            const byteArray = new Uint8Array(byteNumbers);
            byteArrays.push(byteArray);
        }
    
        return new Blob(byteArrays, {type: mimeType});
    }
    
    
    const imageBlob = base64ToBlob(dummyBase64Image, 'image/png');
    
    
    fetch('https://storage.google.apis.com/…', {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/octet-stream',
            'Content-Disposition': 'attachment; filename="dummy.png"'
        },
        body: imageBlob,
    })