Search code examples
javascriptamazon-web-servicesaws-device-farmpre-signed-url

How do I upload a file to a pre-signed URL in AWS?


Problem

I have a pre-signed URL from AWS. I need to upload a file to it. How do I do this?

(I have to use a pre-signed URL. I'm calling the createUpload API for Device Farm, which returns one.)

AWS Documentation gives examples on how to do this in Java, .NET and Ruby. JavaScript is missing.

Attempt 1

I adapted the example here.

const axios = require('axios');
const FormData = require('form-data');

function uploadFile(url, file) {
    if (typeof url !== 'string') {
        throw new TypeError(`Expected a string, got ${typeof url}`);
    }
    const formData = new FormData();
    formData.append(file,file)
    const config = {
        headers: {
            'content-type': 'multipart/form-data'
        }
    }
    return  axios.post(url, formData,config)
}

However I get this error:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

Attempt 2

I got it working with cURL. However, I don't want a dependency on cURL.

const Promise = require('bluebird');
const cmd = require('node-cmd');
const getAsync = Promise.promisify(cmd.get, { multiArgs: true, context: cmd }); 

async function uploadFile(url, fileName) { 
    await throwIfCurlNotInstalled();
    console.log('uploadFile: Uploading file', {
        fileName
    });
    const command = `curl -T ${fileName} "${url}"`;
    try {
        let result = await getAsync(command);
        result.forEach(line => console.log(line));
        console.log('uploadFile: File uploaded', {
            fileName,
        });
    } catch (e) {
        console.error('uploadFile: Error uploading file', {
            fileName
        });
        console.error(e);
    }
}
async function throwIfCurlNotInstalled() {
    try {
        await getAsync(`curl -V`);
    } catch (e) {
        throw 'curl is not installed';
    }
}

Solution

  • The solution was surprisingly simple:

    const rp = require('request-promise');
    const fs = require('fs');
    
    async function uploadFile(url, fileName) {
        let options = {
            method: 'PUT',
            uri: url,
            body: fs.readFileSync(fileName),
        };
    
        return rp(options);
    }