Alexa-skills-kit-sdk-for-nodejs: How to call rest api inside intent

Created on 20 Sep 2016  路  15Comments  路  Source: alexa/alexa-skills-kit-sdk-for-nodejs

i need some help.

I have been following the updated samples but unfortunately none have a call to an API.

Easiest way to explain is to attach a gist!!

In my BookingTimeIntent I want to call github status api for example.

See:
https://gist.github.com/shavo007/a89d82975c9a5420307f0bc7c871b7da

Now without a callback, it will not wait until the response comes back from api.

If i wrap the emit in a callback, i see the response from github in the logs but the emit complains.

Any clue?

Most helpful comment

well, the way you solved your "problem" was by moving the "talking" emit into your getStatus. That doesn't seem right, does it ;).

The reason that getStatus doesn't return your data is because it is an asynchronous call to a service, so it can't return the answer since by the time it gets to the end of the block, it doesn't know the answer yet!

So using a promise is the way to go in this case....

And in doing that, you don't even need bind or call ;)

const request = require("request-promise");
const getStatus = function getStatus() {
    return request.get("https://status.github.com/api/status.json")
}

getStatus().then(
    (response) => {
        console.log(response);
    },
    (error) => {
        console.error('uh-oh! ' + error);
    }
);

you can play with it here:
https://runkit.com/arthur/580f89a2ebb1540013c9d45c

All 15 comments

hey @shavo007,

Would be helpful if you put in the error, but I'm guessing that in your callback, when you call this.emit() the this does not point to what you think it does.

Here's a runkit example of the problem I think you're having: https://runkit.com/arthur/57e15e7c08ae201400e52e5f

get it? Let me know if that doesn't make it clear....

fantastic explanation mate. @acinader

i havent looked at the es6 features yet, but the fat arrow function is what I need.

I did get it working last night but I used a closure using var self = this;. Then i passed this into the function and returned as part of the callback.

eg:
`
var self = this;
sendMessage(self, date, function(self, data) {

        if (data !== undefined) {
            console.log("data is " + JSON.stringify(data));
            speechOutput = "Confirming booking. This may take a few seconds";
        self.emit(':tell', speechOutput);
        } else {
            speechOutput = "Problem with booking. Please try again";
            self.emit(':tell', speechOutput);
        }


    });

`

awesome!

I will try to refactor it to use your approach when I get time. Thanks again

@acinader i need your help mate.

I tried the fat arrow approach but believe i am doing something wrong.

I have a simple function to get github status. Then in my intent i just want to return that response.

var getStatus = function() {
    console.log('get github status');

    var client = new Client();
    client.get("https://status.github.com/api/status.json", function(data, response) {
        // parsed response body as js object

        console.log(data);
        return data;
    }).on('error', function(err) {
        console.log('something went wrong on the request', err.request.options);
    });

}


'BookingIntent': function() {


        // Create speech output

        var speechOutput = "Testing";
        var reprompt = "Testing";


        getStatus((data) => {


            console.log(this);
            console.log('response ' + data);
            this.emit(':ask', speechOutput, reprompt);
        });





    },

I see in the cloudwatch logs that it is outputting the github status in the top function. But I get invalid response from amazon request. Any clue?

@shavo007 you need to bind this to your function: getStatus.call(this) is what you are looking for.

note that if your function took an argument, it would look like: getStatus.call(this, arg1, [arg2,...])

function.call() is similar to function.bind(), but function.call calls the function in addition to binding:

var foo = function foo(say) {
  console.log(this);
  console.log(say);
}

var boundFoo = foo.bind(this);
boundFoo('hi');

// is the same as 
foo.bind(this)('hi');

// is the same as
foo.call(this, 'hi');

thanks for the reply @acinader .

The function executes correctly now. But i was expecting that my function would return the json response. But instead is undefined.

var data = getStatus.call(this); console.log(this); console.log('response ' + data); this.emit(':ask', speechOutput, reprompt);

I return the json response in getStatus function. Should i not see it here?

Thanks,
Shane.

went with bind approach in the end.

getStatus(function(response) {
            console.log(this);
            console.log('response ' + JSON.stringify(response));
            this.emit(':ask', speechOutput, reprompt);
        }.bind(this));

well, the way you solved your "problem" was by moving the "talking" emit into your getStatus. That doesn't seem right, does it ;).

The reason that getStatus doesn't return your data is because it is an asynchronous call to a service, so it can't return the answer since by the time it gets to the end of the block, it doesn't know the answer yet!

So using a promise is the way to go in this case....

And in doing that, you don't even need bind or call ;)

const request = require("request-promise");
const getStatus = function getStatus() {
    return request.get("https://status.github.com/api/status.json")
}

getStatus().then(
    (response) => {
        console.log(response);
    },
    (error) => {
        console.error('uh-oh! ' + error);
    }
);

you can play with it here:
https://runkit.com/arthur/580f89a2ebb1540013c9d45c

awesome @acinader . that worked. i used promises in front end with angular before. when i searched for node rest clients node-rest-client came up and that uses callbacks! promises is alot cleaner and uses the lexical scoping. thanks so much for your help.

馃憤 that was fun. glad you got it worked out.

Hi guys,

I have a similar problem, see my code below - the problem i'm having is when testing with lambda-local and in AWS, it just sits there and times out and never gets to my emit call - i'm probably (definitely) doing something dumb!

`
var handlers = {
'LaunchRequest': function() {
login();
}
};

function login(callback) {

var addProject = commands.buildAddProjectCommand('Alexa Test');

request('https://todoist.com/API/v7/sync?token=a94dsadasdbaf99af213123700b25aefbe43edc7be15c&sync_token=*&commands=' + addProject),

function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Show the HTML for the Google homepage.
var speechOutput = "Calling todoist API. This may take a few seconds";
this.emit(':tell', speechOutput);
}
}
}`

Any ideas?

same problem as above. What do you think this is in your code?

try this:

var handlers = {
  'LaunchRequest': function() { 
    login.call(this);
  }
};

you should also add an error case:
if(error) this.emit(':tell', 'oops!');

@acinader nice one thanks - in the end I had to setup some promises but I passed this in and all was good :-)

Hi guys I am trying to work through a problem where I have an intent but once I read the answer out to the user I want to send an SMS. Do do this I've created a micro service but I can't get the call to fire. Any suggestions on how I should do this would be helpful.

'HouseKeepingIntent': function() {
var Itemslot = this.event.request.intent.slots.Item;
var Itemname = Itemslot.value;
var url = "https://hook.io/farhanmemon/hotel?" +"item=" + Itemname;

if(Itemname == 'towels') {

https.get(url, function(res) {
                    var body = '';

                    res.on('data', function (chunk) {
                            body += chunk;
             });
});
this.attributes['speechOutput'] = this.t("DIRTY", Itemname);
this.attributes['repromptSpeech'] = this.t("DIRTY", Itemname);
}
else
{this.attributes['speechOutput'] = this.t("HOUSEKEEPING_MESSAGE", Itemname);
this.attributes['repromptSpeech'] = this.t("HOUSEKEEPING_REPROMPT", Itemname);}
this.emit(':ask', this.attributes['speechOutput'], this.attributes['repromptSpeech']);

},
Was this page helpful?
0 / 5 - 0 ratings

Related issues

dkl3in picture dkl3in  路  3Comments

dillonharlessNHRMC picture dillonharlessNHRMC  路  6Comments

talkingnews picture talkingnews  路  5Comments

seanfisher picture seanfisher  路  5Comments

z4o4z picture z4o4z  路  3Comments