1

I am using AWS Lambda (Node.js 8.1) for my AWS Lex chatbot which is integrated with facebook and would like to know how to make the bot print out the confirmIntent response (request 1) first and then print the quick replies (request 2).

I have tried a variety of things like adding "request 2" into the same callback as the confirmIntent function, but the quick replies always prints first. I know the issue is because NodeJS is asychronous, but still dont know how to solve it.

function greeting(intentRequest, callback) {
const hello = intentRequest.currentIntent.slots.Hello;
const sessionAttributes = intentRequest.sessionAttributes || {};
const confirmationStatus = intentRequest.currentIntent.confirmationStatus;

var params = null;

var options = {
            uri: 'https://graph.facebook.com/v2.6/'+PSID+'?fields=first_name,last_name,gender&access_token='+process.env.FB_access_token,
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        };

var options_2 = {
            uri: 'https://graph.facebook.com/v2.6/me/messages?access_token='+process.env.FB_access_token,
            body: JSON.stringify({
                recipient: {"id":PSID},
                message: {
                    text: "Here is a quick reply!",
                    quick_replies: [
                            {
                                content_type: "text",
                                title: "Search",
                                payload: "yes",
                                image_url: "http://example.com/img/red.png"
                            },
                            {
                                content_type: "location"
                            }
                        ]
                }
            }),
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            }
        };

/*request 1 - Get FB user data*/          
request(options, function (error, response, body) {
    console.log(error,response.body);

    body = JSON.parse(body);

    params = {
        first_name: body['first_name'],
    };
    callback(confirmIntent(sessionAttributes, 'GetStarted', 
        {
            Age: null,
        },
        { contentType: 'PlainText', content: 'Hi ' +params.first_name+ ', I will guide you through a series of questions to select your own customized product. Are you ready to start?' }));
});

/*request 2 - Quick replies*/
request(options_2, function (error, response) {
            console.log(error,response.body);
        });
}

My confirmIntent function

function confirmIntent(sessionAttributes, intentName, slots, message) {
return {
    sessionAttributes,
    dialogAction: {
        type: 'ConfirmIntent',
        intentName,
        slots,
        message,
    },
};
}
Rohan Jain
  • 11
  • 2

1 Answers1

1
/*request 1 - Get FB user data*/

request(options, function(error, response, body) {
  console.log(error, response.body);

  body = JSON.parse(body);

  params = {
    first_name: body["first_name"]
  };

  const confirmation = confirmIntent(
    sessionAttributes,
    "GetStarted",
    {
      Age: null
    },
    {
      contentType: "PlainText",
      content:
        "Hi " +
        params.first_name +
        ", I will guide you through a series of questions to select your own customized product. Are you ready to start?"
    }
  );

  /*request 2 - Quick replies*/
  request(options_2, function(error, response) {
    console.log(error, response.body);
    callback(null, confirmation);
  });
});

You can do this to make sure second request always happens after first request.

If you have Node Carbon, you can also use async await like this:

/*request 1 - Get FB user data*/
const request = require('request-native-promise') //need this for promises (async await are basically promises)
const response1 = await request(options);
const body = JSON.parse(response1.body);

params = {
    first_name: body["first_name"]
};

const confirmation = confirmIntent(
    sessionAttributes,
    "GetStarted", {
        Age: null
    }, {
        contentType: "PlainText",
        content: "Hi " +
            params.first_name +
            ", I will guide you through a series of questions to select your own customized product. Are you ready to start?"
    }
);

callback(null, confirmation);

/*request 2 - Quick replies*/
const response2 = await request(options_2);
Faizuddin Mohammed
  • 4,118
  • 5
  • 27
  • 51
  • The issue is that it the second request finishes before the first request – Rohan Jain May 22 '18 at 06:07
  • 1
    Won't happen in this case because second request does not event start till the first request is complete. Notice how second request is inside the callback of the firs request. – Faizuddin Mohammed May 22 '18 at 06:19
  • I tried your code, it still prints the quick reply first, i think because when the second request is called, it first logs the `function (error, response)` then does the API call (printing the quick reply button on fb), and then does what ever is in the callback. – Rohan Jain May 22 '18 at 06:48
  • Need to figure out a way for the second request to happen after the `callback(confirmation)` – Rohan Jain May 22 '18 at 06:49
  • 1
    No, the second request can't happen until the first is done here. Make sure you have the right code. Otherwise, I have no idea why this happened. – Faizuddin Mohammed May 22 '18 at 07:12
  • Yes that is correct. but what i want is for the callback(confirmation) to happen first and then for the second request to happen. – Rohan Jain May 23 '18 at 12:02
  • Oh I understand. That depends on the callback function. Maybe you can just do `callback()` and then `secondRequest()` – Faizuddin Mohammed May 23 '18 at 12:08
  • Hey, do you think you could show me how to do it with Async and await? – Rohan Jain May 24 '18 at 05:24
  • Yup.. edited. But it's best if you understand promises first and then go to start using async await as `async await` is just sugar over Promises using generators – Faizuddin Mohammed May 24 '18 at 05:29
  • No it didnt work, still same issue :(. No matter what i try, `callback(confirmintent)` is always the last thing that happens. – Rohan Jain May 24 '18 at 07:27
  • Okay.. do you see logs of second request happening? If not - try doing this: `context.WaitsForEmptyEventLoop = true` - `context` from AWS Lambda – Faizuddin Mohammed May 24 '18 at 07:30