1

I'm using node-gcloud https://github.com/GoogleCloudPlatform/gcloud-node to interact with Google Cloud Storage.

I'm developing a node.js server (my first node.js project) to provide a small set of APIs to clients. Basically when an user uploads a file the API call return the signed url to show that file.

The getSignedUrl function is asynchronous https://googlecloudplatform.github.io/gcloud-node/#/docs/v0.8.1/storage?method=getSignedUrl and I can't find a way to return that result from another function.

I've started playing with Bluebird promises but I can't get to the point of it. Here is my code:

var _signedUrl = function(bucket,url,options) {
  new Promise(function (resolve, reject) {
    var signed_url
    bucket.getSignedUrl(options, function(err, url) {
      signed_url = err || url;
      console.log("This is defined: " + signed_url)

      return signed_url   
    })
  })
}


var _getSignedUrl = function(url) {
  new Promise(function(resolve) {
    var   options = config.gs
      ,   expires = Math.round(Date.now() / 1000) + (60 * 60 * 24 * 14)
      ,   bucket  = project.storage.bucket({bucketName: config.gs.bucket, credentials: config.gs })
      ,   signed_url = null

    options.action  = 'read'
    options.expires =  expires// 2 weeks.
    options.resource= url
    signed_url = resolve(_signedUrl(bucket,url,options))

    console.log("This is undefined: " + signed_url)

    return JSON.stringify( {url: signed_url, expires: expires} );

  });
}

I think that I'm missing the basics of how it is supposed to work, so any hint will be appreciated.

Edit:

I have reworked my solution as for the first comment:

getSignedUrl: function() {
    var   options = config.gs
      ,   expires = Math.round(Date.now() / 1000) + (60 * 60 * 24 * 14)
      ,   bucket  = project.storage.bucket({bucketName: config.gs.bucket, credentials: config.gs })
      ,   signed_url = null

    options.action  = 'read'
    options.expires =  expires// 2 weeks.
    options.resource= this.url

    Promise.promisifyAll(bucket);

    return bucket.getSignedUrlAsync(options).catch(function(err) {
        return url; // ignore errors and use the url instead
    }).then(function(signed_url) {
        return JSON.stringify( {url: signed_url, expires: expires} );
    });
}

It's not clear to me how the double return is supposed to work, but if I keep the return bucket

what I get is this output:

{ url: { _bitField: 0, _fulfillmentHandler0: undefined, _rejectionHandler0: undefined, _promise0: undefined, _receiver0: undefined, _settledValue: undefined, _boundTo: undefined } }

, and if remove it and keep the

return JSON.stringify( {url: signed_url, expires: expires} );

I get undefined as before. What am I missing?

1 Answers1

2

Some points:

  • Inside a new Promise(function(res, rej){ … }) resolver callback, you actually need to call resolve() or reject() (asynchronously), not return anything.
  • resolve doesn't return anything. You seemed to use it like a "wait" operation that returns the result of the promise, but such is impossible. A promise is still asynchronous.
  • Actually, you should never need to call new Promise at all. Use Promisification instead.

Your code should rather look like

var gcloud = require('gcloud');
Promise.promisifyAll(gcloud); // if that doesn't work, call it once on a
                              // specific bucket instead

function getSignedUrl(url) {
    var options = config.gs,
        expires = Math.round(Date.now() / 1000) + (60 * 60 * 24 * 14),
        bucket  = project.storage.bucket({bucketName: config.gs.bucket, credentials: config.gs });

    options.action  = 'read';
    options.expires =  expires; // 2 weeks.
    options.resource = url;
    return bucket.getSignedUrlAsync(options).catch(function(err) {
        return url; // ignore errors and use the url instead
    }).then(function(signed_url) {
        console.log("This is now defined: " + signed_url);
        return JSON.stringify( {url: signed_url, expires: expires} );
    });
}
Bergi
  • 513,640
  • 108
  • 821
  • 1,164