3

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

3 Answers 3

2

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);
    }
  },
};
Sign up to request clarification or add additional context in comments.

Comments

1

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();
        });
    },
};

Comments

-1

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.

1 Comment

I tried that and it didn't work either. I am not sure how to go about making asynchronous calls when it comes to sending responses to alexa.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.