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';
}
}
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);
}