Thanks your work on this, I've found it much easier to use than other AoG/DialogFlow libraries despite being in early beta.
With the latest update (removing builders), there's a problem with callback/promises in handler functions, specifically when doing HTTP requests. I believe it is a combination of the removal of agent.send() and the way HTTP client libraries do callback (possibly not preserving 'this' reference as needed?).
Something like this works as expected:
function myFunc (callback) {
// Do something
callback();
}
function anotherFunc() {
agent.add('My Response');
}
myFunc(anotherFunc);
However, if you try this (request library, callback)
request('http://www.google.com', (error, response, body) => {
agent.add('Hello');
});
Or with axios (Promise-based)
axios.get('https://google.com')
.then(response => {
agent.add('My response');
})
.catch (error => {
// do something
})
You get the following error
Error: No responses defined for null
at V1Agent.sendResponse_ (/user_code/node_modules/dialogflow-fulfillment/v1-agent.js:119:13)
at WebhookClient.send_ (/user_code/node_modules/dialogflow-fulfillment/dialogflow-fulfillment.js:225:19)
at promise.then (/user_code/node_modules/dialogflow-fulfillment/dialogflow-fulfillment.js:285:38)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
I've played around with this a bit and I'm not sure what exactly the issue is. It seems related to how these HTTP clients handle callback and losing the 'this' reference, obviously both request and axios are very popular HTTP clients. An easy fix seems like adding back agent.send(), but I'm not sure if the plan is to remove that.
function handlers support promises now so you can return a promise and process things like http requests in the promise. Here is an example of using the request library:
function dialogflowHanlderWithRequest(agent) {
return new Promise((resolve, reject) => {
request.get(options, (error, response, body) => {
JSON.parse(body)
// processing code
agent.add(...)
resolve();
});
});
};
You can also move the HTTP call to another function that returns a promise. Here is an example with the axios library:
function dialogflowHandlerWithAxios(agent) {
return callApi('www.google.com').then(response => {
agent.add('My response');
}).catch (error => {
// do something
})
};
function callApi(url) {
return axios.get(url);
}
Does this satisfy your use case?
Thank you - this clears up my issues! Keep up the great work on this.
Thanks! will do. I'll add a sample/documentation demonstrating this at some point.
Hello Matthewayne,
Subject: Dialogflow Fulfillment
Few days earlier i was able to execute the code properly and the output was returned to the bot.
But now i am not getting any response as on bot.The logs from firebase show that API Call is successful and the response is returned correctly. But unable to share the result with user.
Code is as follow.
function getLatLng(agent) {
let city = agent.parameters['geo-city'];
url=url+city;
//agent.add(url);
callWeatherApi(city,agent).then(() => {
//agent.add( output ); // Return the results of the weather API to Dialogflow
}).catch(() => {
//res.json(`I don't know the weather but I hope it's good!` );
});
agent.add(`Welcome to the Weather Function!`);
//agent.add(`I can Show Weather Latitude & Longitude`);
}
function callWeatherApi (city,agent) {
return new Promise((resolve, reject) => {
console.log('API Request: ' + url);
// Make the HTTP request to get the weather
console.log('Starting http Call');
http.get(url, (res) => {
console.log('Inside http Call 1');
let body = ''; // var to store the response chunks
var bodyChunks = [];
res.on('data', (d) => { body += d;}); // store each response chunk
res.on('end', () => {
// After all the data has been received parse the JSON for desired data
let response = JSON.parse(body);
console.log(response);
let lat=response.results[0].geometry.location.lat;
let lon=response.results[0].geometry.location.lng;
console.log('Current Latitude is'+lat+' '+lon);
let output='Current Latitude & Longitude for'+city+' is '+lat+' / '+lon;
agent.add(output);
// Resolve the promise with the output text
console.log(output);
resolve();
});
res.on('error', (error) => {
console.log(`Error calling the weather API: ${error}`);
reject();
});
});
console.log('Finished http Call');
});
}
Your help would be appreciated, Thank you !!!
Did you fix the problem? I'm with the same.
Inside of request, method agent.add now working.
agent.add( JSON.stringify(body))
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
function dialogflowHanlderWithRequest(agent) {
console.log("dialogflowHanlderWithRequest");
agent.add("dialogflowHanlderWithRequest()");
var request = require('request');
var jsonX = {} ;
jsonX.requisicao = "aaaaaaa";
jsonX.page_id = "7777777";
return new Promise((resolve, reject) => {
request.post({
url: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
body:jsonX,
json: true
}, function(error, response, body){
console.log(JSON.stringify(body));
agent.add( JSON.stringify(body));
resolve();
});
});
}
Most helpful comment
function handlers support promises now so you can return a promise and process things like http requests in the promise. Here is an example of using the request library:
You can also move the HTTP call to another function that returns a promise. Here is an example with the axios library:
Does this satisfy your use case?