Athomas
Athomas

Reputation: 573

Lambda function not returning response to Alexa skill

I have a Lambda function for an Alexa skill which is written in Nodejs. It makes an HTTP call to a service and returns the output to the Alexa Skill. When the skill is invoked, the lambda is called, and the HTTP call is made. However, before the HTTP response is returned, the lambda returns, hence the skill does not get an answer.

Below is my Lambda function

var Alexa = require('ask-sdk');
var http = require('http');
var SKILL_NAME = 'Some Facts';

var GetNewFactHandler = {
  canHandle(handlerInput) {
  var request = handlerInput.requestEnvelope.request;
  return request.type === 'LaunchRequest'
  || (request.type === 'IntentRequest'
    && request.intent.name === 'GetNewFactIntent');
},
handle(handlerInput) {
    getTop("", (data)=>{
    let speechOutput = "The result is " + data;
        console.log("resp from lambda ", speechOutput)
        var respSpeak =  handlerInput.responseBuilder
        .speak(speechOutput)
        .withSimpleCard(SKILL_NAME, data)
        .getResponse();
        console.log("respSpeak ", respSpeak);
        return respSpeak;
    });
  },
};


function getTop(query, callback) {
   var options = {
        host: 'somehost',
        port: '8100',
        path: '/top',
        method: 'GET',
   };

    var req = http.request(options, res => {
        res.setEncoding('utf8');
        var responseString = "";

        res.on('data', chunk => {
            responseString = responseString + chunk;
        });

        res.on('end', () => {
            console.log("********",JSON.parse(responseString).Name);
            let respStr = JSON.parse(responseString).Name;
            callback(respStr);
        });

    });
    req.end();
}

In the lambda logs, I can see the logs in getTop(). But the response of the lambda returns before the response of the HTTP call is received. I was thinking that building the response in the callback would ensure that the response is returned only after the HTTP call completes. But that doesn't seem to be the case. How can this be fixed? Any help is appreciated.

Upvotes: 0

Views: 796

Answers (1)

Ussama Zubair
Ussama Zubair

Reputation: 1218

Node.js is asynchronous by default, which means that your response builder is called before the data is returned by the service. I've had similar issue while calling the customer profile api to get phone number, I solved it using async-await like this

async handle(handlerInput) {
    const { serviceClientFactory, responseBuilder } = handlerInput;
    try {
      const upsServiceClient = serviceClientFactory.getUpsServiceClient();
      const profileMobileObject = await upsServiceClient.getProfileMobileNumber();
     
      const profileMobile = profileMobileObject.phoneNumber;
      const speechResponse = `Hello your mobile number is, ${profileMobile}</say-as>`;
      const cardResponse = `Hello your mobile number is, ${profileMobile}`
      return responseBuilder
                      .speak(speechResponse)
                      .withSimpleCard(APP_NAME, cardResponse)
                      .getResponse();
    } catch (error) {
      console.log(JSON.stringify(error));
      if (error.statusCode == 403) {
        return responseBuilder
        .speak(messages.NOTIFY_MISSING_PERMISSIONS)
        .withAskForPermissionsConsentCard([MOBILE_PERMISSION])
        .getResponse();
      }
      console.log(JSON.stringify(error));
      const response = responseBuilder.speak(messages.ERROR).getResponse();
      return response;
    }
  },

Make the function async and use await before you call the service.. You can also do this by Promises

Upvotes: 3

Related Questions