2

So I'm trying to build my first webapp with Facebook integration (using facebook-node-sdk). I have it making simple calls to the api, but now it's time to put this all in a simple server and make the calls upon request (this isn't going to be the webapp, itself, but more of an API server).

The problem I'm running into is that, even though I've (presumably) used bluebird to Promisify the Facebook sdk and my makeCall method, I'm still getting "hi" printed and then "undefined" - console.log is getting called before makeCall can return anything.

Here's my app.js:

var Promise = require('bluebird')
    , http = require('http')
    , Facebook = Promise.promisifyAll(require('facebook-node-sdk'))
    , config = require('./config')
    , fb = new Facebook({ appId: config.fb.api, secret: config.fb.secret });

var makeCall = new Promise.method(function (username) {
    return fb.api(username, function(err, data) {
        console.log('hi')
        if (err) return err;

        return data;
    });
});

http.createServer( function (req, res) {
    makeCall('/me').then(console.log)
}).listen(8001);
Charlie G
  • 814
  • 9
  • 22

2 Answers2

7

new Promise.method doesn't make sense here (or anywhere since it's a function and not a constructor) nor does makeCall.

Try this:

var Promise = require('bluebird')
    , http = require('http')
    , Facebook = require('facebook-node-sdk')
    , config = require('./config')
    , fb = new Facebook({ appId: config.fb.api, secret: config.fb.secret });

Promise.promisifyAll(Facebook.prototype);

http.createServer( function (req, res) {
    fb.apiAsync('/me').then(function (data) {
        console.log(data)
    })
}).listen(8001);

Don't create wrappers when promisifyAll does it for you :)

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • Well, the purpose of `makeCall` is to define my api call outside of the server creation to possibly reuse later. I do concede that `new Promise.method` isn't necessary, though. – Charlie G Jan 20 '14 at 17:37
  • @charlieg no I mean you can just call `fb.apiAsync` instead of creating wrapper – Esailija Jan 21 '14 at 07:19
  • Ah okay. My question really revolved around using Promises, though, and the ability to use the resolve/reject functions is really important to me, here. – Charlie G Jan 22 '14 at 14:35
  • @charlieg `fb.apiAsync` already returns a promise (The method was added by `promisifyall`). All the work you are doing is for essentially making a promise, however it is complete waste when you can use methods that return promises to begin with... – Esailija Jan 22 '14 at 15:05
  • Ohhh yes, you're correct. Can you spell that out a little clearer in your answer? Then I'll mark yours as correct. Thanks! – Charlie G Jan 22 '14 at 19:45
3

The problem was that I was neither returning a Promise nor was I resolving said un-returned promise. Here's the fixed code (that works!)

var Promise = require('bluebird')
    , http = require('http')
    , Facebook = Promise.promisifyAll(require('facebook-node-sdk'))
    , config = require('./config')
    , fb = new Facebook({ appId: config.fb.api, secret: config.fb.secret });

var makeCall = new Promise.method(function (username) {
    return new Promise(function (resolve) {
        // resolve
        console.log('resolve')
        fb.api(username, function(err, data) {
            console.log('err: ' + err)
            console.log('data: ' + data)
            if (err) reject(err);

            resolve(data);
        });
    });
});

http.createServer( function (req, res) {
    makeCall('/me').then(function (data) {
        console.log(data)
    })
}).listen(8001);

Where the output looks like:

resolve
err: null
data: [object Object]
{ id: ... }
Charlie G
  • 814
  • 9
  • 22