Multipart uploads

How can I upload larger files? How can I upload faster?

You may (sometimes have to) upload files in parts. This means instead of opening a single HTTP connection to transfer the whole binary to the REST API, you open multiple connections. Each HTTP connection ships part of the file.

Using multipart uploads enables the following features.

  • Avoiding timeouts when uploading larger files.

  • Increasing the upload speed by uploading the parts concurrently.

  • Pausing the upload.

Multipart upload is a must for uploads which require HTTP connection longer than the REST API timeouts. Multipart upload is recommended for uploading files that are larger than 5 MB. That size also constitutes the minimum size of the upload part (the last chunk may be smaller). The maximum number of chunks is 10,000. The sizes of chunks must be equal (the exception is the last chunk which may be smaller). The chunk size is defined with the first upload chunk, based on Content-Range header.

Example 3. Multipart upload

// Get total file size
const stats = await fs.promises.stat(FILE_PATH);
const fileSize = stats.size;

// Define function for uploading single chunk from the file
const uploadChunk = async (start: number, end: number, headers: HeadersInit = {}) => {
    const chunkStream = fs.createReadStream('./path/to/file', { start: start, end: end });
    const chunk = await arrayBuffer(chunkStream)
    const response = await fetch(`https://api.akord.com/files?tags=${tagsBase64Encoded}`, {
        method: 'POST',
        headers: {
            'Api-Key': 'your_api_key',
            'Content-Type': 'application/pdf',
            'Content-Range': `bytes ${start}-${end}/${fileSize}`,
            ...headers
        },
        body: chunk
    });

    if (response.status !== 202) {
        throw new Error('Failed to upload first chunk of the file. Status code: ' + response.status);
    }
    return response;
}

// Upload first chunk of the file
const response = await uploadChunk(0, CHUNK_SIZE);

// Read location of the multipart upload
const contentLocation = response.headers.get('Content-Location');
if (!contentLocation) {
    throw new Error('Content-Location header is missing');
}

// Upload middle chunks of the file using 'Content-Location' & 'Content-Range' - can be done concurrently
let sourceOffset = CHUNK_SIZE;
const chunkUploadPromises = [];
while (sourceOffset + CHUNK_SIZE < fileSize) {
    const chunkUploadPromise = uploadChunk(sourceOffset, sourceOffset + CHUNK_SIZE, { 'Content-Location': contentLocation });
    chunkUploadPromises.push(chunkUploadPromise);
    sourceOffset += CHUNK_SIZE;
}
await Promise.all(chunkUploadPromises);

// Upload last chunk of the file to complete the multipart upload
const res = await uploadChunk(sourceOffset, fileSize, { 'Content-Location': contentLocation });

Response:

HTTP Status: 202
HTTTP Headers:
    'Content-Location': 'file-id:multipart-upload-id'

Check out other examples in our REST API tests repo. You can also have a look at our SDK code.

Last updated