Alicia Sykes
Alicia Sykes

Reputation: 7107

Node js - How to correctly use make async network calls within a module

So for part of a project I am working on I have created a module that uses the Facebook graph API to make calls and return JSON data. I can console.log() the data within the method out fine and it's all good.

But I can not return the values from the methods, so I tried to use the 'async' npm module. I have followed the examples on the website, but still am struggling to get everything working, spent all day on it so far and still things arn't looking any clearer.

So what I am asking is:

Here is a snippit of my original module (only works with console.log, can't return)

module.exports = {
        /**
         * Pass the access token to the fbgraph module
         * and call other methods to populate
         */
         setUp: function (access_token) {
             graph.setAccessToken(access_token);
         },

        /**
         * Fetches users basic info:
         * Age, Gender, Hometown, Relationship status
         */
        getBasicInfo: function(){
            graph.get("/me/", function(err, res) {
                var result = {
                    'age'       : _calculateAge(res.birthday),
                    'gender'    : res.gender,
                    'hometown'  : res.hometown.name,
                    'relationship_status' : res.relationship_status
                };
                //console.log(result);
                return result;
            }, function(){ console.log("DONE");});
        },
        /**
         * Creates a body of text as a string
         * made up of all the users status updates
         */
        getPosts: function(){
            graph.get("/me/feed?limit="+PHOTO_LIMIT, function(err, res) {
                var posts = "";
                for(var i=0;i<res.data.length;i++){
                    var obj = res.data[i];
                    if(obj.message!=undefined) posts += obj.message+"\n";
                }
                //console.log(posts);
                return {'posts':posts};
            });
        },
        /**
         * Fetches a single dimension string array of
         * photos user is tagged in
         */
        getPhotos: function(){
            graph.get("/me/photos?limit="+PHOTO_LIMIT, function(err, res) {
                var photos = [];
                for(var i=0;i<res.data.length;i++){
                    var obj = res.data[i];
                    photos.push(obj.source); // .source is full size image, .picture is a thumbnail
                }
                return {'photos': photos};
            });
        }
     }

The rest of this module continues in a similar way I have tried using parralel async

module.exports = {
    getFacebookInfo: function (access_token) {
        results = {};
        setUp(access_token);
        async.parallel([
            facebookDataRequests.getBasicInfo(),
            facebookDataRequests.getPosts()

Any guidence on how I should structure this would be very much appreciated, thanks in advance

Upvotes: 0

Views: 420

Answers (1)

Tobi
Tobi

Reputation: 31479

I'd recommend that you structure this differently. It's not necessary to make three calls to Facebook, because you can get the info in one call as well.

So, what I'd do:

  1. Call the Facebook Graph API using field expansion
  2. Format results
  3. Return results

Also, I'd advise you to use a Promise library like Q

Something like this (untested!):

module.exports = {
    getFacebookInfo: function (access_token) {

        setUp(access_token);

        function setUp(access_token) {
             graph.setAccessToken(access_token);
         }

        function getFBInfo() {
            var deferred = Q.deferred();
            graph.get("/me?fields=id,name,birthday,gender,hometown,relationship_status,feed.limit(25),photos.limit(25)", function(err, res) {
                if (err) deferred.reject(err);
                deferred.resolve(res);
            });
            return deferred.promise
        }

        function handleResult(result) {
            var deferred = Q.deferred();

            result.posts = result.feed.data
            delete result.feed.data;

            result.photos = result.photos.data
            delete result.photos.data;

            deferred.resolve(result);

            return deferred.promise
        }

        Q.fcall(getFBInfo)
        .then(handleResult)
        .then(function(result) {
            return result;
        })
        .catch(function (error) {
            // Handle any error from all above steps
        })
        .done();
    }
}

In your main file:

var FB = require('./path/to/file/above');

var results = FB.getFacebookInfo('ACCESS_TOKEN_SDAIOFHIOSDHFOSO');

Upvotes: 1

Related Questions