I am playing with ASK SDK v2 provided by Amazon in order to make Skill for Alexa but I face an architectural problem :
First of all, the HTTP request works like a charm but I would like to return speach response if and only if my HTTP request is complete but I don't even know if it's possible because of the "handle" function that should return something (look at comments) :
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
var req = http.request(options, function(result){
result.on("end", function(){
//I would like to return speak here like that :
//return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse()
})
});
req.end();
//And I would like to remove this line to manage response in result.on("end", function(){}) above
return handlerInput.responseBuilder.speak("It works").withSimpleCard("MyTestApp", "It works").getResponse();
},
};
Any idea to deal with this ?
It abstracts the complexities of making requests behind a simple interface, and makes HTTP requests easy and simple. If you're using Alexa Hosted as the backend for your skills, there's an added advantage of the Requests library being built-in, so you don't need to install or upload it manually.
You can use Lambda functions to build services that give new skills to Alexa, the Voice assistant on Amazon Echo. The Alexa Skills Kit provides the APIs, tools, and documentation to create these new skills, powered by your own services running as Lambda functions.
One simple way to debug this issue is copying the input JSON from Alexa skill simulator and paste it in the lambda's configure test events. Now run test and it'll generate all the error logs in the lambda itself, for your easy reference.
I found the official way to make it :
1) Create a new funtion that manage http request and return a promise :
function httpGet(options) {
return new Promise(((resolve, reject) => {
const request = http.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
if (response.statusCode < 200 || response.statusCode >= 300) {
return reject(new Error(`${response.statusCode}: ${response.req.getHeader('host')} ${response.req.path}`));
}
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.on('error', function (error) {
reject(error);
});
request.end();
}));
}
2) In the Intent, return a promise in which you call your httpGet function :
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'MyIntent');
},
handle(handlerInput) {
var options = {
host: 'http://foo.com',
port: 80,
path: '/mypath',
method: 'GET'
};
return new Promise((resolve, reject) => {
httpGet(options).then((response) => {
resolve(handlerInput.responseBuilder.speak("It is done.").getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('Thor is not available at the moment. Please try again later or contact your administrator.')
.getResponse());
});
});
},
};
This is the way to do it properly. My example is base on alexa petmatch sample.
Also we can use request module to call API as follows
const SearchIntentHandler = {
canHandle(handlerInput) {
return (
handlerInput.requestEnvelope.request.type === "IntentRequest" &&
handlerInput.requestEnvelope.request.intent.name === "SearchIntent"
);
},
handle(handlerInput) {
const query = handlerInput.requestEnvelope.request.intent.slots.SearchQuery.value;
return new Promise((resolve, reject) => {
getSearchResults(query).then((response) => {
resolve(handlerInput.responseBuilder.speak(response).getResponse());
}).catch((error) => {
resolve(handlerInput.responseBuilder.speak('This is not available at the moment.').getResponse());
});
});
}
};
function getSearchResults(query){
return new Promise((resolve, reject)=>{
let options = {
method: 'POST',
url: 'http://url.com',
headers: {'Cache-Control': 'no-cache','Content-Type': 'application/x-www-form-urlencoded' },
form: { text: query }
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
let data = body ? JSON.parse(body) : ""
return resolve(data);
});
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With