-1

I am new to Javascript and just got stuck with async callbacks with Javascript using Node.js.

I first set up the Facebook webhook and make a Webhook POST request

Here is my code : routes.js

**To set up facebook webhook**

var facebook_handler = require('../controllers/botkit').handler

module.exports = function (app) {
  // public pages=============================================
  // root
  app.get('/', function (req, res) {
    res.render('home')
  })

  app.get('/webhook', function (req, res) {
    // Check to see which webhook password (FACEBOOK_VERIFY_TOKEN) to check for, from incoming request.
    if (process.env.PORT ||process.env.VCAP_APP_PORT ) {
      FB_VERIFY_TOKEN = process.env.FACEBOOK_VERIFY_TOKEN
    } else {
      FB_VERIFY_TOKEN = process.env.FACEBOOK_VERIFY_TOKEN_DEV
    }
    // This enables subscription to the webhooks
    if (req.query['hub.mode'] === 'subscribe' && req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
      res.send(req.query['hub.challenge'])
    }
    else {
      res.send('Incorrect verify token')
    }
  })

  app.post('/webhook', function (req, res) {
    console.log("\n CALL HANDLER FUNCTION ---- \n");
    facebook_handler(req.body)
    console.log("call handler done");
    res.send('okay')
  })
}

From Above code, i make a POST request to Facebook webhook and get the details of the FB message and then process the webhook POST request in another file BotKit.js

Botkit.js

var request = require('request');
require('dotenv').load();

var handler = function (obj) {
console.log("Message received from FB \n");

  if (obj.entry ) {
    for (var e = 0; e < obj.entry.length; e++) {
           for (var m = 0; m < obj.entry[e].messaging.length; m++) {
                var facebook_message = obj.entry[e].messaging[m]
                test_message = facebook_message.message.text;
                translatorEnglish (test_message) // calling the watson translator api to get translation for the received facebook message.
     }
   }
}

Above code process webhook POST request and call the Translator function ( translation POST request )

Translator Function

  var translationusername = "1234"
  var translationpassowrd = "1234"
  var transURL = "https://gateway.watsonplatform.net/language- 
  translator/api/v2/translate";

  translatorEnglish = function(test_message) {
           console.log("this should be called when translator called:" +test_message);
            var parameters = {
             text: test_message,
              model_id: 'es-en'
            };
            languageTranslator.translate(
              parameters,
              function(error, response, body) {
                if (error)
                  console.log(error)
                else
                  english_message = response.translations[0].translation
                  console.log("The response should be:" +english_message);
                  translate = false
                  //console.log(JSON.stringify(response, null, 2));
              }
            );
          };

The problem is the translation POST request is not executed until the Call Handler i.e the webhook POST request is completed. The translation POST request always executes after Webhook POST is completed.

Is there are way i can execute the Translator POST request within the Webhook POST request before the Webhook POST request is complete.

Something like this Webhook POST --> execute --> Translation POST execute and complete ---> Webhook POST complete

aram
  • 71
  • 1
  • 10

1 Answers1

0

First of all,languageTranslator.translate function is an async function so it returns and doesn't waits for it's callback to be done. So if you want to be sure that the callback finished, you should do the next commands after it's finished by utilizing new callbacks or promise.then function.

Secondly, your translatorEnglish function neither have callback, nor is a promise. Hence, nobody waits for its async function call (languageTranslator.translate) to be finished. Thus, You should change it to either a promise format or callback format (also you can use async await format which is like promise).

Thirdly, anyway translatorEnglish function will be an async function and you want to use it inside a for loop in handle function which means you may have more than one async function to wait for and it makes it hard to be handled using callback. So I suggest you to use promise in this case and in order to wait for all promises to be completed you can use Promise.all function.

Don't forget, you should make all those functions promise and call res.send in facebook_handler().then function.

extras:

  • If you want to convert a function with callback to promise without changing its implementation (promisify) you can use node 8 util.promisify or bluebird Promise.promisify functions.

  • Take a look at this question and answer too.