1

I have a code snippet for generating a signed url. The below return statement always returns empty url. Rest of the data is correctly resolved. When I debug I see that the return callback gets executed first then the resolve part of the function validSignedURL gets called.

awsHelper
        .s3vldSignedURL(s3Link)
        .then(function(signedURL) {
            data[1].url = signedURL;
            return callback(null, successResponse.getResponse(context, 'OK', data));
        });

The s3vldSignedURL maps to the function below. Here s3.headobject is promise based, used to check if a file exists in s3. I want this function to be generic, so that I can use it to generate a signed url, for any s3object.

function validSignedURL(bucket, path) {
console.log("Generating Presigned Link ... ");
const s3 = new aws.S3();

let params = {
    Bucket: bucket,
    Key: path
};

let checkObj = s3.getObject(params);
return new Promise(function(resolve, reject){
    s3.headObject(params).promise()
        .then(function (data) {
            console.log('s3 File exists' + data);
            resolve(getSignedURL(bucket, path));
        }).catch(function (err) {
        console.log('Generating Presigned Link ... Failed' + err);
        resolve('');
    });
});
}

The below function getSignedURL always returns a signed url irrespective of the object exists or not.

function getSignedURL(bucket, path) {
    console.log("Generating Presigned Link ... ");
    const s3 = new aws.S3();

    let params = {
        Bucket: bucket,
        Key: path
    };

return s3.getSignedUrl('getObject', params);
}

Also, how can I convert the function call s3.headObject(params) to a synchronous call which returns true or false?

user 923227
  • 2,528
  • 4
  • 27
  • 46
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Aug 25 '17 at 00:44
  • Also see the [difference between `.then(…, …)` and `.then(…).catch(…)`](https://stackoverflow.com/q/24662289/1048572), which doesn't however explain why you are seeing `resolve` after the `callback` either (unless that's not your actual code). – Bergi Aug 25 '17 at 00:51
  • 1
    "*How can I convert the function call `s3.headObject(params)` to a synchronous call*" - you cannot. Don't try. – Bergi Aug 25 '17 at 00:51
  • Another question is, do you really need to know if the object doesn't exist? Creating a pre-signed URL against a non-existent object **is a valid action** because the pre-signed URL will be valid if the object exists in the future, and will return a `404` error if the pre-signed URL is used used until then (or if the object is never created). – Michael - sqlbot Aug 25 '17 at 02:33
  • `validSignedURL` always resolves, sure it resolves `''` on error, but you don't seem to check the resolved value in your code – Jaromanda X Aug 25 '17 at 04:07
  • @JaromandaX Yes, I just assign it to `data[1].url` in the first code block. – user 923227 Aug 25 '17 at 18:11
  • @Bergi Hi, with the promise constructor anti pattern are you asking me to try `return s3.headObject(params).promise()` in place of `return new Promise(function(resolve, reject){` with the call as - `data[1].url = awsHelper. validSignedURL('invndata', s3Link + mapFileName);` this too behaves in the same nature. The return takes place before. – user 923227 Aug 25 '17 at 18:58
  • 1
    @SumitKumarGhosh Yes, that's what you should replace. No, this still returns a promise from `validSignedURL` (you can't prevent that), but then its written properly. – Bergi Aug 25 '17 at 22:20
  • You solved it ? – Maykonn Oct 20 '17 at 13:15
  • Somehow managed through. I will share the solution. – user 923227 Oct 20 '17 at 17:11

1 Answers1

1

This is the complete function definition and calling for AWS signed url if the object exists using promises. If you are using AWS Lambda you need to add s3 permissions.

  • If there is no need to validate if the url exists then getSignedURL is the function to be used
  • If there is a need to check if the object exists then use validSignedURL it will return an empty url if not found.

Here is how I implemented it:

function getSignedURL(bucket, path) {
    console.log("Generating Presigned Link ... ");

    let params = {
        Bucket: bucket,
        Key: path
    };

    //expires in default 15 mins.
    return s3.getSignedUrl('getObject', params);
}

function validSignedURL(bucket, path) {
    console.log("Generating Presigned Link ... ");
    let params = {
        Bucket: bucket,
        Key: path
    };

    return new Promise(function(resolve, reject){
        s3.headObject(params).promise()
            .then(function (data) {
                console.log('s3 File exists' + data);
                resolve(getSignedURL(bucket, path));
            }).catch(function (err) {
            console.log('Generating Presigned Link ... Failed' + err);
            resolve('');
        });
    });
}

Calling the function and resolving the promise. I have some other fields populated before in data which is returned along with the signed url.

    validSignedURL(bucketName, s3Link + fileName).then(function(signedURL) {
        data.url = signedURL;
        return callback(null, successResponse.getResponse(context, 'OK', data));
        });
user 923227
  • 2,528
  • 4
  • 27
  • 46