user1366265
user1366265

Reputation: 1436

Calling a REST API from a Lambda function

I am trying to build a skill that calls a REST API to get data. I am using the HelloWorld sample and modifying it to fit my need. I am using the Request node (node.js) to issue the request.

However, for the hell of me I can't get it to work. I see in the log that the function is called and the correct result is coming back, yet the response sent to Alexa is empty!! Any idea what I am missing?

const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    console.log("HelloWorldIntentHandler 1: ");
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  handle(handlerInput) {
    console.log("HelloWorldIntentHandler 2");
    var speechText = 'Hello World';

    Request.get(url, function(error, response, body) {
      console.log("I'm here")
      var data = JSON.parse(body)
      var result = data.records.totalNum
      if (result > 0) {
          speechText = "There are " + result + " matches";
      } else {
          speechText = "ERROR";
      }

      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Hello World', speechText)
        .getResponse();
     });
  },
};

The error in the log is

Error handled: speechOutput.trim is not a function

Upvotes: 3

Views: 1538

Answers (3)

Rob White IV
Rob White IV

Reputation: 91

For what it is worth, I ran into the same issue and found out (the hard way) that the response I was returning from my api call contained text that was not properly formatted for SSML ( String returned contained an '&' in my case ).

So I found this lib that seems to not only help, but generally be a good idea to use if you can't be 100% sure of your result.

See: https://www.npmjs.com/package/ssml-builder

Hope this helps someone.

~Rob

I guess I better add a code example too. This is not tested, but is what your code might look like using the lib I mentioned there ^^^.

const Speech = require( 'ssml-builder' );

const HelloWorldIntentHandler = {
    canHandle(handlerInput) {
        console.log("HelloWorldIntentHandler 1: ");
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
               && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
    },
    handle(handlerInput) {
        console.log("HelloWorldIntentHandler 2");
        let speechText = 'Hello World';

        Request.get(url, function(error, response, body) {
            console.log("I'm here");
            let data = JSON.parse(body);
            let result = data.records.totalNum;
            if (result > 0) {

                let speech = new Speech();
                speech.say(`There are ${result} matches`);
                speechText = speech.ssml(true);

            } else {
                speechText = "ERROR";
            }

            return handlerInput.responseBuilder
                               .speak(speechText)
                               .withSimpleCard('Hello World', speechText)
                               .getResponse();
        });
    },
};

Upvotes: 1

user1366265
user1366265

Reputation: 1436

I was able to get this to work using Axios instead of Request.

const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    console.log("HelloWorldIntentHandler 1: ");
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  async handle(handlerInput) {
    console.log("HelloWorldIntentHandler 2");
    var speechText = 'default';

    try {
      const response = await Axios.get(url);
      var result = response.data.totalRecs;
      if (result > 0) {
          speechText = "There are " + result + " matches";
      } else {
          speechText = "ERROR";
      }
      console.log("text=" + speechText);
      return handlerInput.responseBuilder
        .speak(speechText)
         .withSimpleCard('Hello World', speechText)
         .getResponse();
    } catch (error) {
      console.log(error);
    }
  },
};

Upvotes: 2

bgsuello
bgsuello

Reputation: 692

Put your return inside the if else statement.

  Request.get(url, function(error, response, body) {
    console.log("I'm here")
    var data = JSON.parse(body)
    var result = data.records.totalNum

    if (result > 0) {
      speechText = "There are " + result + " matches";
      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Hello World', speechText)
        .getResponse();
      });
    } else {
      speechText = "ERROR";
      return handlerInput.responseBuilder
         .speak(speechText)
         .withSimpleCard('Hello World', speechText)
         .getResponse();
      });
    }
  } 

This will force your handler to return the result in your if else statement.

Upvotes: -1

Related Questions