Question: util.promisify converts an async function that uses the error-first callback style to a Promise. However it doesn't seem to work with AWS' S3.upload (scroll down to .upload) which is an async function that uses the error-first callback format.

Original format:

const params = {Bucket: 'bucket', Key: 'key', Body: stream};
s3.upload(params, function(err, result) {
    if (err) {
        throw new Error(err);
    } else {
        console.log(result);
    }
});

Promisify format:

const params = {Bucket: 'bucket', Key: 'key', Body: stream};
const s3Upload = util.promisify(s3.upload);
s3Upload(params)
    .then( (result) => {
        console.log(result);
    })
    .catch( (err) => {
        throw new Error(err);
    });

However used in this manner s3.upload throws an error,

TypeError: service.getSignatureVersion is not a function

If util.promisify doesn't necessarily work for every async function that uses a callback is there a way to determine beforehand if a function will work with it? Or alternately does it take trial and error to determine if util.promisify will work?

2

There are 2 best solutions below

0
jfriend00 On BEST ANSWER

Geoffrey has explained why this probably doesn't work for the code you tried, but even better would be to use the promise support built-into the AWS interface:

const params = {Bucket: 'bucket', Key: 'key', Body: stream};
s3.upload(params).promise().then((result) => {
    console.log(result);
}).catch( (err) => {
    console.log(err);
    throw err;
});

AWS documentation here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html

3
Geoffrey Casper On

Before answering your question, I'd like to point out that callback style functions are usually not async functions. util.promisify wraps a callback style function with a promise, which is the same thing as wrapping the callback style function in an async function.

To fix your issue you may need to properly set the this context for the upload funciton manually. That would look something like this:

const s3Upload = util.promisify(s3.upload.bind(s3));

Otherwise, the issue you are having is either a Node.js bug or a AWS bug, and I would reccommend filing a bug report.