Google Action connected to Firebase function unable to call external api? - node.js

Currently I have a google action built using the ActionSDK with NodeJS where the fulfillment is hosted on Firebase cloud functions. All I am trying to do right now is just pass the input from google action to an external api but it seems like it is unable to send it through?
'use strict';
const {actionssdk} = require('actions-on-google');
const functions = require('firebase-functions');
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
const app = actionssdk({debug: true});
app.intent('actions.intent.MAIN', (conv) => {
conv.ask('Hello, this is Patrick.');
});
app.intent('actions.intent.TEXT', (conv, input) => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.googleapis.com/customsearch/v1?key={apikey}&cx={searchID}&q=" + input, true);
xhr.send();
xhr.onreadystatechange = function () {
conv.ask(this.readyState.toString());
}
exports.myFunction = functions.https.onRequest(app);
But this always gives me the response of:
My test app isn't responding right now. Try again soon.
And in the error tab it displays:
{
"error": "No response has been set. Is this being used in an async call that was not returned as a promise to the intent handler?"
}
I have no idea why this happens as I'm new to this whole thing. Any help is appreciated!

If you are using a free tier of firebase you will not be allowed to use external APIs. You will need to enable billing and upgrade to a paid tier to access.
UPDATE
You may need to use Promise to send back a response. Check out this issue.

Related

Firebase cloud functions throws timeout exception but standalone works fine

I am trying to call a third party API using my Firebase cloud functions. I have billing enabled and all my other function are working fine.
However, I have one method that throws Timeout exception when it tries to call third API. The interesting thing is, when I run the same method from a standalone nodeJS file, it works fine. But when I deploy it on Firebase cloud or start the function locally, it shows timeout error.
Following is my function:
exports.fetchDemo = functions.https.onRequest(async (req, response) =>
{
var res = {};
res.started = true;
await myMethod();
res.ended = true;
response.status(200).json({ data: res });
});
async function myMethod() {
var url = 'my third party URL';
console.log('Line 1');
const res = await fetch(url);
console.log('Line 2'); // never prints when run with cloud functions
var data = await res.text();
console.log(`Line 3: ${data}`);
}
Just now I also noticed, when I hit the same URL in the browser it gives the following exception. It means, it works only with standalone node.
<errorDTO>
<code>INTERNAL_SERVER_ERROR</code>
<uid>c0bb83ab-233c-4fe4-9a9e-3f10063e129d</uid>
</errorDTO>
Any help will be appreciated...
It turned out that one of my colleague wrote a new method with the name fetch. I was not aware about it. So when my method was calling to the fetch method, it was actually calling his method he wrote down the file. I just took git update and did not notice he wrote this method.

Is there a way to instantiate a new client on server side by firebase cloud function?

I am developing an app and trying to implement news feed by getstream.io using react native and firebase.
Is there a way to generate user token by using firebase cloud function. If there is, would you please give me a pointer how i can do so? (the snippet of codes in cloud function side and client side would be super helpful..)
I have seen similar questions, only to find out no specific tutorial.. any help is appreciated!
For the cloud function side you need to create a https.onRequest endpoint that calls createUserToken like so:
const functions = require('firebase-functions');
const stream = require('getstream');
const client = stream.connect('YOUR_STREAM_KEY', 'YOUR_STREAM_SECRET', 'YOUR_STREAM_ID');
exports.getStreamToken = functions.https.onRequest((req, res) => {
const token = client.createUserToken(req.body.userId);
return { token };
});
After that, deploy with firebase deploy --only functions in the terminal & get the url for the function from your firebase dashboard.
Then you can use the url in a POST request with axios or fetch or whatever like this:
const { data } = axios({
data: {
userId: 'lukesmetham', // Pass the user id for the user you want to generate the token for here.
},
method: 'POST',
url: 'CLOUD_FUNC_URL_HERE',
});
Now, data.token will be the returned stream token and you can save it to AsyncStorage or wherever you want to store it. Are you keeping your user data in firebase/firestore or stream itself? With a bit more background I can add to the above code for you depending on your setup! 😊 Hopefully this helps!
UPDATE:
const functions = require('firebase-functions');
const stream = require('getstream');
const client = stream.connect('YOUR_STREAM_KEY', 'YOUR_STREAM_SECRET', 'YOUR_STREAM_ID');
// The onCreate listener will listen to any NEW documents created
// in the user collection and will only run when it is created for the first time.
// We then use the {userId} wildcard (you can call this whatever you like.) Which will
// be filled with the document's key at runtime through the context object below.
exports.onCreateUser = functions.firestore.document('user/{userId}').onCreate((snapshot, context) => {
// Snapshot is the newly created user data.
const { avatar, email, name } = snapshot.val();
const { userId } = context.params; // this is the wildcard from the document param above.
// you can then pass this to the createUserToken function
// and do whatever you like with it from here
const streamToken = client.createUserToken(userId);
});
Let me know if that needs clearing up, these docs are super helpful for this topic too 😊
https://firebase.google.com/docs/functions/firestore-events

How to get external api data using inline editor in dialogflow

I've got a Dialogflow agent for which I'm using the Inline Editor (powered by Cloud Functions for Firebase). When I try to get external api data by using request-promise-native I keep getting Ignoring exception from a finished function in my firebase console.
function video(agent) {
agent.add(`You are now being handled by the productivity intent`);
const url = "https://reqres.in/api/users?page=2";
return request.get(url)
.then(jsonBody => {
var body = JSON.parse(jsonBody);
agent.add(body.data[0].first_name)
return Promise.resolve(agent);
});
}
Your code looks correct. The exception in this case might be that you're not using a paid account, so network access outside Google is blocked. You can probably see the exact exception by adding a catch block:
function video(agent) {
agent.add(`You are now being handled by the productivity intent`);
const url = "https://reqres.in/api/users?page=2";
return request.get(url)
.then(jsonBody => {
var body = JSON.parse(jsonBody);
agent.add(body.data[0].first_name)
return Promise.resolve(agent);
})
.catch(err => {
console.error('Problem making network call', err);
agent.add('Unable to get result');
return Promise.resolve(agent);
});
}
(If you do this, you may want to update your question with the exact error from the logs.)
Inline Editor uses Firebase. If you do not have a paid account with Firebase, you will not be able to access external APIs.

How to call youtube api in Firebase Function Spark mode

I am using Firebase for first time. I manage Firebase to store the data in database and send external http rquest not working.
I am calling Youtube api to get data. I am reading many answers here saying only google owned api are allowed. My code doesn't work on sending request to youtube api.
Someone please check and help.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
var req = require('request');
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
exports.helloWorld = functions.https.onRequest((request, response) => {
var url = "https://www.googleapis.com/youtube/v3/commentThreads?part=id,snippet,replies&allThreadsRelatedToChannelId=abcd&maxResults=100&order=time&key=key"
req(url, function (error, resp, body) {
if (!error && resp.statusCode === 200) {
return resp;
// var comments = JSON.parse(body);
// comments.forEach(comment => {
// var dataid = com.snippet.topLevelComment.id;
// var docRef = db.collection("comments").doc(dataid);
// var storeInDB = docRef.set(comment);
// });
}
});
response.send("hello World");
});
This function does work fine when I just return the response so I think, Youtbe api thing work fine, But when I uncomment the code which does parse the response and trying to store it in database I see this
Function execution started
6:46:31.736 PM
outlined_flag
helloWorld
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove these restrictions
6:46:31.829 PM
outlined_flag
helloWorld
Function execution took 94 ms, finished with status code: 200
In Spark mode, you won't be able to make a call to YouTube API since it isn't supported.
Firebase still thinks that you are calling external API which requires billing setup.
Use Blaze plan which is pay as you go. It feels like the most expensive plan since it is located in the far right. Yet, it includes free tier quota. Once it goes over then you will be charged. You can set low budget to cap it. Then it becomes basically same free tier with billing setup.

Accessing the content of events in Javascript?

I'm trying to get a print out of the events my cloud function is privy to. I tried console.log(event)in the Atom console but I get this error:
Uncaught Error: Cannot find module 'firebase-functions'
at Module._resolveFilename (module.js:455:15)
at Module._resolveFilename
I'm not familiar with Javascript or Atom, so I don't know why I'm not getting the expected behaviors, my guess is that I need to authorize the script that is trying to access my secure backend on Firebase.
Here's my cloud function so far:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPushNotification = functions.database.ref('/
iMessenger/{Messages}/{id}').onWrite(event => {
//I really want to see all that's inside of 'event'. How do I see this info??
console.log(event)
const payload = {
notification: {
title:'New message arrived',
body:'Hello World',
badge:'1',
sound:'default',
}
};
return admin.database().ref('/iMessenger/{Messages}/{id}/toUserDisplayName').once('value').then(allToken => {
if (allToken.val()){
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token, payload).then(response => {
});
};
});
});
using console.dir(event) will list every available method and parameter within event
Console.log(event) shows up in your cloud function logs in firebase. And the missing module was because my editor couldn’t exactly interface with the firebase modules I figure, as firebase accepts my functions and the notification are coming through; a testament to successful implementation.

Resources