2
votes

Having issues making a REST call to an API between a node.js Lambda function and Alexa. I'm using the request library to make the calls with an account linked skill. I've only set one sample utterance for the intent, and the simulator see this fine.

Also, the cloudwatch logs show a 200 response code from the api endpoint and any of the returned data from the API from console.logs to CW.

'use strict';
var http = require('http');
var request = require('request');
var Alexa = require('alexa-sdk');
var APP_ID = "amzn1.ask.skill.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX";

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
   'LaunchRequest': function () {
        this.emit(':tell', 'Hi!');
   },

   'ApiWelcomeIntent': function () {
        request('https://some.web/api', function (error, response, body) {
            if (!error && response.statusCode == 200) {
            // from within the callback, write data to response, essentially returning it.
                var speechOutput = JSON.stringify(body);
                console.log(body + " :Raw output?");
                console.log(speechOutput + ' :JSON stringified');
                console.log(response.statusCode);
                this.emit(':tell', speechOutput);
            } else {
                console.log(error + ' : ' + response.statusCode);
                this.emit(':tell', 'There was an error');
            }
        });
    },

    'AMAZON.HelpIntent': function () {} //.........And other built in intents.

    }
};

I'm guessing its something to do with the format of speechOutput that I'm asking Alexa to "emit/tell"?

2

2 Answers

4
votes

No, it has nothing to do with the format of speechOutput. The issue is that when the callback of the request method is executed, the reference to this is lost. To solve that, keep a reference to this before you call request (e.g. assign this to a variable called self):

'use strict';
var http = require('http');
var request = require('request');
var Alexa = require('alexa-sdk');
var APP_ID = "amzn1.ask.skill.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX";

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
   'LaunchRequest': function () {
        this.emit(':tell', 'Hi!');
   },

   'ApiWelcomeIntent': function () {
        self = this

        request('https://some.web/api', function (error, response, body) {
            if (!error && response.statusCode == 200) {
            // from within the callback, write data to response, essentially returning it.
                var speechOutput = JSON.stringify(body);
                console.log(body + " :Raw output?");
                console.log(speechOutput + ' :JSON stringified');
                console.log(response.statusCode);
                self.emit(':tell', speechOutput); // USE SELF HERE
            } else {
                console.log(error + ' : ' + response.statusCode);
                self.emit(':tell', 'There was an error'); // AND HERE AS WELL
            }
        });
    },

    'AMAZON.HelpIntent': function () {} //.........And other built in intents.

    }
};
0
votes

You are facing issue only because of asynchronous call behavior of NodeJS and nothing to do with request call. You can solve this either by using promises or by using callback from method. Below is snippet.

'use strict';
var http = require('http');
var request = require('request');
var Alexa = require('alexa-sdk');
var APP_ID = "amzn1.ask.skill.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX";

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
   'LaunchRequest': function () {
        this.emit(':tell', 'Hi!');
   },

   'ApiWelcomeIntent': function () {
        requestAPI( (message) => {
            this.emit(':tell', message);
        });
    },
    'AMAZON.HelpIntent': function () {} //.........And other built in intents.

    }
};

function requestAPI(callback) {
    request('https://some.web/api', function (error, response, body) {
        if (!error && response.statusCode == 200) {
        // from within the callback, write data to response, essentially returning it.
            var speechOutput = JSON.stringify(body);
            console.log(body + " :Raw output?");
            console.log(speechOutput + ' :JSON stringified');
            console.log(response.statusCode);
            callback(speechOutput);
        } else {
            console.log(error + ' : ' + response.statusCode);
            callback('There was an error');
        }
    });
}