Using Google People API with Cloud Functions for Firebase - node.js

I'm trying to get a list of contacts from the Google People API with Cloud Functions for Firebase but I'm only getting an empty object as the response. Any thoughts? Cloud Functions code below:
var functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var google = require('googleapis');
var people = google.people('v1');
exports.contacts = functions.https.onRequest((request, response) => {
admin.database().ref('/settings/contacts/credentials/serviceAccount').once("value", function(data) {
var authClient = new google.auth.JWT(
data.child('clientEmail').val(),
null,
data.child('privateKey').val(),
['https://www.googleapis.com/auth/contacts'],
null
);
authClient.authorize(function (err, tokens) {
if (err) {
console.error(err);
response.end();
return;
}
// Make an authorized request to list contacts.
people.people.connections.list({auth: authClient, resourceName: 'people/me'}, function(err, resp) {
if (err) {
console.error(err);
response.end();
return;
}
console.log("Success");
console.log(resp);
response.send(resp);
});
});
});
});
In the Firebase console logs, the success message is printed along with the empty JSON object. Seems to be authorizing successfully so not quite sure what's going on. Any help would be greatly appreciated.

Try wrapping the api call in a Promise. I had a similar issue until I wrapped mine in a promise. Also in the specific example linked to here I needed to use response.data and not response.labels with the the resolve part of the promise. console.log() will be your best friend here.
https://cloud.google.com/community/tutorials/cloud-functions-oauth-gmail
https://github.com/GoogleCloudPlatform/community/blob/master/tutorials/cloud-functions-oauth-gmail/index.js

Related

Lambda function only works once

So I'm new to AWS serverless architecture. I deployed my first lambda function using Claudia. I'm not sure whether I did it correctly. I deployed all the APIs to one lambda function using Claudia. The API endpoints works individually when I test it on Insomnia. But when I use it in my application only one specific API works and the lambda dies. For instance, I used this POST request to post some items and I have a useEffect in my React application which has a get request to retrieve all the items from the database. But once I post the item, nothing is returned. Could anyone help me understand what I'm doing wrong. P.S this is my final year project which is due in a few weeks. So, a quick answer would be appreciated.
Here is a sample code.
// Create a new Intake
router.post("/create", async (req, res) => {
const intake = req.body;
const { name, intakeCode, intakeYear } = req.body;
const checkIntake = await Intakes.findOne({
where: {
intakeCode: intakeCode,
},
});
if (checkIntake) {
res.json({ err: `An intake under ${intakeCode} already exists!` });
} else {
try {
await Intakes.create(intake);
res.json({ msg: `Successfully created ${name} ` });
} catch (e) {
if (e.name == "SequelizeDatabaseError") {
res.json({ err: "Year only accepts integer" });
} else {
res.json({ err: e.name });
}
}
}
});
// Find all Intakes
router.get("/findAll", async (req, res) => {
const listOfIntakes = await Intakes.findAll();
res.json(listOfIntakes);
});
Cheers
Looks like you are trying to build a Lambda function using JavaScript - but have encountered problems. I'm not familiar with Claudia. One suggestion that I have is to follow the official AWS SDK for JavaScript DEV Guide here:
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/scheduled-events-invoking-lambda-example.html
That content will walk you through how to create a Lambda function using JS.

how to read specific data from realtime database in node.js

I am working on API Get request. I have created a POST request to add the data in firebase realtime database. The code is as follows:
// CREATE POST
app.post("/post", (req, res) => {
let key;
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in.
var newPost = firebase.database().ref("posts/");
var myPost = newPost.push({
createdBy: user.uid,
from: req.body.from,
to: req.body.to,
duration: req.body.duration,
comments: req.body.comments,
});
res.send(newPost);
const postId = myPost.key;
console.log(postId);
} else {
// No user is signed in.
res.status(404).send("No user is signed in right now!");
}
});
});
Now, in order to get a specific post, I have written the following code:
// GET SPECIFIC POST
app.get("/post/:id", (req, res) => {
let response;
firebase
.database()
.ref("posts/" + req.params.id)
.on("value", (snapshot) => {
response = snapshot.val();
});
res.send(response);
});
I am new at Firebase, so I dont really know how to get a specific post. Please help me out
Calls to Firebase are asynchronous, because they require a call to the server. While that call is happening, your main code continues. And then when the data is available, your callback is invoked with the data from the server.
Right now your res.send(response) runs before the response = snapshot.val() is ever called. The rule with asynchronous APIs is simple: any code that needs the data needs to be inside the callback, or be called from there.
So in your case:
app.get("/post/:id", (req, res) => {
firebase
.database()
.ref("posts/" + req.params.id)
.once("value")
.then((snapshot) => {
res.send(snapshot.val());
});
});
You'll note that I also change from on to once, since you only care about getting the value once (instead of attaching a permanent listener that monitors the database for changes).
Dealing with asynchronous API is a common stumbling block, so I recommend spending some time reading these answers to learn more:
Why Does Firebase Lose Reference outside the once() Function?
Firebase response is too slow
Best way to retrieve Firebase data and return it, or an alternative way
I simply did this:
app.get("/post/:id", (req, res) => {
var key = req.params.id;
console.log(key);
firebase
.database()
.ref("posts")
.child(key)
.get()
.then((snapshot) => {
res.send(snapshot.val());
});
});
this solved the problem

AWS SES create template with lambda function always return null

so on my first time learning AWS stuff (it is a beast), I'm trying to create e-mail templates, I have this lambda function:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: "us-east-1" });
exports.handler = async (event, context, callback) => {
// Create createTemplate params
var params = {
Template: {
TemplateName: "notification" /* required */,
HtmlPart: "HTML_CONTENT",
SubjectPart: "SUBJECT_LINE",
TextPart: "sending emails with aws lambda"
}
};
// Create the promise and SES service object
const templatePromise = new AWS.SES({ apiVersion: "2010-12-01" })
.createTemplate(params)
.promise();
// Handle promise's fulfilled/rejected states
templatePromise
.then((data) => {
console.log(data);
callback(null, JSON.stringify(data) );
// also tried callback(null, data);
}, (err) => {
console.error(err, err.stack);
callback(JSON.stringify(err) );
});
as far as I am understanding, this function should return me a template? an object, anything? when I use the lambda test functionality I always got null in the request response
does anyone know what I am doing wrong here?
edit: and It is not creating the e-mail template, I check the SES Panel - email templates and it is empty
edit2: if I try to return a string eg: callback(null, "some success message"); it does return the string, so my guess is something wrong with the SES, but this function is exactly what we have in the AWS docs, so I assume it should just work..
Try not to resolve the Promise and change your code to just returning it as-is:
return await templatePromise;
which should present you some more detail of what is really going wrong in your code - it might be some hidden access issue - so you might need to adjust the role your lambda function is using. createTemplate on the other side should not return much in case of successful execution but just create the template.
Also try to follow the following try/catch pattern when using async (as described here in more detail: https://aws.amazon.com/de/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/)
exports.handler = async (event) => {
try {
data = await lambda.getAccountSettings().promise();
}
catch (err) {
console.log(err);
return err;
}
return data;
};

Error: getaddrinfo ENOTFOUND in node.js webhook for dialogflow

I am trying to follow the dialogflow tutorial. I have set up a node.js webhook, that is called from Dialogflow, inside the webhook code I call out to an api. However, my node.js webhook is saying "Error: getaddrinfo ENOTFOUND". This works fine when I run it in visual code but cannot find the api with in the nodejs webhook, when called via DialogFlow. There is something about the fact that it is being called from Dialogflow that seems to be making it not work.
I have spent a lot of time on this, and had previsouly discovered that DialogFlow wont work with https where it is a self signed certificate, as such I put an azure function, so the webhook calls the azure function and then the azure function call the api that I need.
Sorry for the long post...
Here is the node.js code:
'use strict';
const http = require('http');
var request = require('request');
const apiUrl ="https://myapi";
exports.saledurationWebhook = (req, res) => {
// Get the city and date from the request
// let city = req.body.queryResult.parameters['geo-city']; // city is a required param
let city = "sdjk";
// Call the weather API
callSalesDurationApi(city).then((output) => {
res.json({ 'fulfillmentText': output }); // Return the results of the weather API to Dialogflow
})
.catch((err) => {
console.log(err);
//res.json({ 'fulfillmentText': `I don't know the sales duration is but I hope it's quick!` });
res.json({ 'fulfillmentText': err.message});
})
;
};
function callSalesDurationApi(city) {
return new Promise((resolve, reject) => {
console.log('API Request: ' + apiUrl);
var myJSONObject = {
"Inputs": "stuff"
};
request({
url: apiUrl,
method: "POST",
json: true, // <--Very important!!!
body: myJSONObject
}, function (error, response, body) {
console.log("successfully called api");
let output = "Current conditions in the " + body;
console.log(output);
console.log(body);
resolve(output);
});
});
}
Does anyone know why this might be happening? Or what frther steps I can take to investigate it? I have already looked at the loges for the webhook, and for the azure function.
Any help would be really gratefully recieved, I have already wasted days on this. If this is a duplicate question then I am sorry, I have tried to look for existing answers on this issue.
Thanks Laura
I have found this question already answered at: https://stackoverflow.com/a/46692487/7654050
It is because I have not set billing up for this project. I thought it been set up as it is on my work account.

Send response back to client after google compute engine api call in node js

I am trying to get the Kubernetes cluster details from google cloud using google cloud Kubernetes API for node js.
Below is the example i have found in google documentation.
var google = require('googleapis');
var container = google.container('v1');
authorize(function(authClient) {
var request = {
projectId: 'my-project-id',
zone: 'my-zone',
clusterId: 'my-cluster-id',
auth: authClient,
};
container.projects.zones.clusters.get(request, function(err, response){
if (err) {
console.error(err);
return;
}
// TODO: Change code below to process the `response` object and send the detail back to client.
console.log(JSON.stringify(response, null, 2));
});
});
function authorize(callback) {
google.auth.getApplicationDefault(function(err, authClient) {
if (err) {
console.error('authentication failed: ', err);
return;
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
var scopes = ['https://www.googleapis.com/auth/cloud-platform'];
authClient = authClient.createScoped(scopes);
}
callback(authClient);
});
}
As the google get API is asynchronous function, how can I return the response from API back to client.
The question is what do you want to do with the data? It's not an issue of the API being asynchronous or not, this snippet of code should return in the console the same JSON you would get with this request:
GET https://container.googleapis.com/v1beta1/projects/[PROJECT ID]/locations/[ZONE]/clusters/[CLUSTER NAME]
The function and callback should take care of the fact that it's asynchronous.

Resources