I'm trying to make my own google action and I want to call an external api to get responses.
Here is my code:
const { conversation } = require('@assistant/conversation');
const functions = require('firebase-functions');
const app = conversation({debug:true});
const https = require('https');
app.handle('Tester', conv => {
// Implement your code here
conv.add("ok it works");
});
app.handle('Tester2', conv => {
// Implement your code here
let url = 'https://jsonplaceholder.typicode.com/users?_limit=2';
//const url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
http_req(url).then((message)=> {
console.log(message[0].name);
conv.add(message[0].name);
//return Promise.resolve();
});
});
function http_req(url) {
return new Promise((resolve, reject) => {
https.get(url, function(resp) {
var json = "";
resp.on("data", function(chunk) {
//console.log("received JSON response: " + chunk);
json += chunk;
});
resp.on("end", function() {
let jsonData = JSON.parse(json);
console.log(jsonData[0].name);
resolve(jsonData);
});
}).on("error", (err) => {
reject("Error: " + err.message);
});
});
}
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
Error text:
Error: Response has already been sent. Is this being used in an async call that was not returned as a promise to the intent handler?
The problem is that the assistant won't say the conv.add(message[0].name); (obviusly it has a value)
Thanks in advance!
Thanks to a reddit user https://www.reddit.com/r/GoogleAssistantDev/comments/lia5r4/make_http_get_from_fulfillment_in_nodejs/gn23hi3?utm_source=share&utm_medium=web2x&context=3
This error messages tells you just about all you need to know! Your call to con.add() is indeed being used in an asynchronous call (the callback chained to the Promise you created from http_req), and you are indeed not returning that Promise.
Here's what's happening:
Google calls your 'Tester2' handler
You start an asynchronous HTTP request via http_req, encapsulated in a Promise
Your function completes before the HTTP request does
Google sees that you are not returning anything from your handler and assumes that you're done, so it sends the Response
The HTTP request finishes and its Promise resolves, calling your code attached by the then() function
The simple solution here is to return the Promise created by your http_req(...).then(...) code, so Google will know that you're not just quite done, and it should wait for that Promise to resolve before sending the Response.
If you can use async/await it becomes a bit clearer:
app.handle('Tester2', async conv => {
// Implement your code here
let url = 'https://jsonplaceholder.typicode.com/users?_limit=2';
//const url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
const message = await http_req(url);
console.log(message[0].name);
conv.add(message[0].name);
});