3

I'm trying to make a chain of promises functions which use HTTP requests in NodeJS with Kraken framework.

My code could work in 90% of cases, but if the distant requested server takes time to respond, the code will return an error with undefined values. So I think Q is a good solution to prevent that.

Here's the situation :

We access to a URL with a "code" parameter -> the route controller takes this param to use it in a HTTP POST request -> the response (a token) is stored in a variable and used in an other HTTP GET request -> the response (multiple JSON objects) is stored in variable too -> all variables are stored in a MongoDB. If functions are not used in this order, of course it fails.

var Q = require('q');

module.exports = function (router) {
  router.get('/', function (req, res) {
    var codein = req.param('code');
    if(codein){
        console.log('Provided code: ' + codein+'\n');
        getAccessToken(codein).then(function(token){
            console.log('Provided AccessToken: ' + token + '\n');
            getUsername(token).then(function(userdata){
                console.log('Provided Username: ' + JSON.parse(userdata).username + '\n');
                storeData(userdata).then(function(msg){
                    console.log(msg);
                    res.redirect('/dashboard/' + JSON.parse(userdata).username);
                });
            });
        });

    }
    else{
        console.log('Access Denied, redirecting...');
        res.redirect('/');
    }
  });
};

This method works, but actually didn't resolve the problem, because sometimes variable are undefined again. I think it's my request functions which aren't well made...

Here's an example of the first function with POST request :

var getAccessToken = function(cod){
    var def = Q.defer();
    var data = querystring.stringify({
            client_id:"1234567890", 
            client_secret:"******", 
            grant_type:"authorization_code", 
            redirect_uri:"http://localhost:8000/r/callback", 
            code:cod
    });

    var options = {
        host: 'domain.server.com',
        port: 443,
        path: '/api/oauth2/token',
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': Buffer.byteLength(data)
        }
    };

    var response = "";

    var req = https.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            response += chunk;
        });

        res.on('end', function(){
            var json = JSON.parse(response);
            var acto = json.access_token;
            def.resolve(acto);

        });
    });

    req.write(data);
    req.end();
    return def.promise;

};

In this case the acto variable can be undefined... So am I using Q in a wrong way ?

EDIT

To understand my problem, let me show you what can I have in my output console (really rare but happens) :

Provided code: 12345678910

Provided Username: user543210

Instead of :

Provided code: 12345678910

Provided AccessToken: 9876543210

Provided Username: user
jbltx
  • 1,255
  • 2
  • 19
  • 34
  • Maybe read http://stackoverflow.com/questions/22539815/arent-promises-just-callbacks ? – Benjamin Gruenbaum Aug 05 '14 at 06:22
  • Are you sure, `access_token` is present in the `json` always? – thefourtheye Aug 05 '14 at 06:27
  • @thefourtheye Yes I'm sure, if you want to know I'm currently using Twitch API and I have to store my accessToken to put it in requests' header. Undefined variables appear only when the Twitch server takes time to respond. – jbltx Aug 05 '14 at 06:30

1 Answers1

2

I think you need to account for 2 scenarios

  1. Where the Twitch API takes time to respond.
  2. The Twitch response cannot be parsed

The code

    res.on('end', function(){
        var json = JSON.parse(response);
        var acto = json.access_token;
        def.resolve(acto);
    });

Should be modified as:

    try {    
       var json = JSON.parse(response);
       var acto = json.access_token;
       //check if acto is undefined
       if (acto === undefined) {
         def.reject('Some error message');
       } else {
         def.resolve(acto);
       }
    } catch (error) {
      //since the JSON could not be parse
      def.reject(error);
    }
Anand Sunderraman
  • 7,900
  • 31
  • 90
  • 150