Google Cloud HTTP function by webhook: Request body is missing data - node.js

Im integrating the Zoom API with my Firebase app, and to do so I'm relying on Zooms pre-made webhooks to run an HTTP function on my Firebase for various events like "meeting started" and "meeting ended". Zoom API reference: https://marketplace.zoom.us/docs/guides/webhooks
This is the Google Cloud function that the Zoom API is calling:
exports.zoomTestA = functions.https.onCall((req, res) => {
console.log(req);
let data = req.body;
var xmlData = data.toString();
console.log(xmlData);
});
Here is the payload sent by Zoom:
{
"event": "meeting.ended",
"payload": {
"account_id": "LTf-KjgUTR2df-knT8BVEw",
"object": {
"duration": 0,
"start_time": "2019-05-07T14:02:51Z",
"timezone": "",
"topic": "Alexander Zoom Meeting",
"id": "864370042",
"type": 1,
"uuid": "2h/SWVrrQMu7fcbpLUly3g==",
"host_id": "Ty6ykNolSU2k1N4oc0NRcQ"
}
}
This causes this error to appear in my Google Cloud console:
Request body is missing data. { event: 'meeting.ended',
payload:
{ account_id: 'LTf-KjgUTR2df-knT8BVEw',
object:
{ duration: 0,
start_time: '2019-04-30T14:23:44Z',
timezone: '',
topic: 'Alexander\'s Zoom Meeting',
id: '837578313',
type: 1,
uuid: 'WotbHO3RRpSviETStKEGYA==',
host_id: 'Ty6ykNolSU2k1N4oc0NRcQ' } } }
The request body that Zoom sends is not wrapped in in a "data: {}" tag as required by Google Cloud functions. I've found solutions to this problem if you can control the payload here: Dart json.encode is not encoding as needed by Firebase Function .
My problem is that I am unable to alter the request that the Zoom API sends. Is there any way I can still accept the request in my Google Cloud function? Or is there any way to alter the format of the request sent by Zoom? I'm unable to find references for either.
One potential solution would be to set up another server that receives the request by Zoom, format it to Google Cloud functions specifications, and then pass it on to my Google Cloud function. I would however like to avoid stepping out of the Google Cloud eco-system.
Is this problem solvable on the Google Cloud platform?

So I figured it out. In Firebase / Google Cloud functions you can either make HTTP-functions with
functions.https.onCall((req, res) => {
var data = req.body;
and
functions.https.onRequest((req, res) => {
var data = req.body;
The difference seems to be that onCall is made for being used within the Firebase/ Google Cloud functions environment. However if you wan external functions you need to use onRequest as this does not require specific formatting of the payload.
Using onRequest instead solved all my problems.

Related

Node.Js get data from a POST request

Im using Firebase cloud functions. On an iOS device, im deploying a trigger to run a cloud function in Node.Js. In Xcode - here is my client function to trigger the Cloud function - I'm passing over the dictionary data
func updateTermsOfServiceCloudCall(){
let data = [
"accountId": "acct_1Ew#######"
]
Functions.functions().httpsCallable("updateAccountWithTOA").call(data) { (result, error) in
}
Now in Node, i'm running this code to deploy to the Firebase cloud
exports.updateAccountWithTOA = functions.https.onRequest((request, response) => {
const data = request.body;
const accoundId = data.accoundId;
stripe.accounts.update(
accoundId,
{
tos_acceptance: {
date: Math.floor(Date.now() / 1000),
ip: request.ip
}
},
)
});
I'm expecting to get the dictionary data that i passed over from my iOS client. However, im having an issue getting that data in Node. I thought request.body would give me the data, but i guess im wrong because i an getting this error. Any help or suggestions would be appreciated. Thanks
Error: Stripe: Argument "id" must be a string, but got: undefined (on
API request to POST /accounts/{id})
Your client code is trying to invoke a callable function, but your function is defined as an HTTP type function. They are different things. You can't invoke a regular HTTP function using the Functions SDK.
If you want to use the Functions SDK to invoke a function, it needs to be defined with onCall rather than onRequest, as shown in the documentation for callable functions. Or, if you don't want a callable on the backend, you will need to invoke the regular HTTP function with an HTTP client library.

Getting status of Google Cloud transfer Job

I am using node.js utility of google cloud transfer api to transfer data from s3 bucket to my Google Cloud bucket using
#1
storagetransfer.transferJobs.create(request, function (err, response)
And once it is completed i want to proceed with with some functionality.
To check the status of transfer Job there is an api
#2
storagetransfer.transferOperations.get(request, function(err, response)
which takes
var request = {
// The name of the operation resource.
name: 'transferOperations/my-transfer-operation',
auth: authClient,
};
as parameter.
I cant seem to find what is the value that need to be input'ed in place of "my-transfer-operation"
The response received from "storagetransfer.transferJobs.create" has a data object with {name: 'transferJobs/2469904309496821948'}, but this value is not working for "my-transfer-operation" value.
I need to get value of "my-transfer-operation" which can be used a parameter for getting status of my transfer job using #2 api.
source : https://cloud.google.com/storage-transfer/docs/reference/rest/v1/transferOperations/get
You can use transferOperations.list, which you can test here, putting in the request name : 'transferOperations' and filter : "{"project_id" : "<your-project-id>"}".
The response will contain an array of operations with a structure starting like
{
"operations": [
{
"name": "transferOperations/transferJobs-<id-from-transferJobName>-<another-id>",
"metadata": {
...
"status": "<some-status>", //e.g. IN_PROGRESS
...
},
...
and that long name, containing the id you were trying to use, is what you need to input to transferOperations.get. You can also obtain the status directly from that response, as you see.

Google analytics steps to get number of views per page from an API

I want to start somewhere.
This is my use case.
I have a restAPI written in node.js express framework.
I have a mobile application written in the react native.
Also I have a web application for the administration purpose of the mobile app, written in Vue.js
Mobile app is food app. Where you can search restaurants or dishes of a restaurant.
I want to pass the restaurant id and get the restaurant views of the app with in the last 7 days.
Pretty straight forward requirement. But hard to implement. Since I don't know where to start from.
I went through the docs and have found there are 7 APIs.
Core reporting API
Management API
Embed API
User deletion API
Multi channel reporting API
Real time API
Meta data API
End of the day, I would love to do something similar to this with the API.
showMeTheView(restaurant_id)
Also If I want to pass additional parameter to say get only last month views count.
showMeTheViews(restaurant_id, last_month)
I can't figure out what are the essential steps to achieve my requirement?
What need to be done in the react-native app?
What need to be done in the vue.js web app?
What need to be done in between these two?
First off you should be using the Core reporting api this is the api that can be used to extract data from Google analytics. The Json object used to extract data form Google analytics is quite extensive batch get
It will make your life a lot easier if you use the Google apis node.js client libray
code ripped from sample found here
'use strict';
const {google} = require('googleapis');
const sampleClient = require('../sampleclient');
const analyticsreporting = google.analyticsreporting({
version: 'v4',
auth: sampleClient.oAuth2Client,
});
async function runSample() {
const res = await analyticsreporting.reports.batchGet({
requestBody: {
reportRequests: [
{
viewId: '65704806',
dateRanges: [
{
startDate: '2018-03-17',
endDate: '2018-03-24',
},
{
startDate: '14daysAgo',
endDate: '7daysAgo',
},
],
metrics: [
{
expression: 'ga:users',
},
],
},
],
},
});
console.log(res.data);
return res.data;
}
// if invoked directly (not tests), authenticate and run the samples
if (module === require.main) {
const scopes = ['https://www.googleapis.com/auth/analytics'];
sampleClient
.authenticate(scopes)
.then(runSample)
.catch(console.error);
}
// export functions for testing purposes
module.exports = {
runSample,
client: sampleClient.oAuth2Client,
};

Stripe module issues at Parse

I am developing a project which integrates Stripe + Parse for iOS. It uses web hooks and Cloud code via node js. Currently i am in need of implementing a couple of functions:
cancel user subscription with flag atPeriodEnd;
subscribe cancelled customer once again (named multiple subscriptions via Stripe docs).
As for the first one: I'm sending a request as follows in Parse's API -
Stripe.Customers.cancelSubscription(request.params.customerID, 1, null)
but the second parameter, i.e. atPeriodEnd remains 0 when i receive Stripe's response and my webhook catches request for cancelling user immediately. Also i have checked Stripe's dashboard to see parameters that i pass and it says 'No query parameters'. Hope you can help me with this one out.
Second one: as i mentioned earlier user needs to have ability to subscribe once again after cancellation. That means that i already have a valid customer saved at Stripe and all i need is to 'attach' to him a new subscription. There is a method for this at Stripe docs:
stripe.customers.createSubscription("cus_00000000000", { plan: "planName" }, function(err, subscription) {
});
But i can't find similar to this in Parse's API. Hope you can help with this one out.
Sorry if there are some mistakes or misunderstandings for you - feel free to ask, i will answer as much clear as i can. Thanks!
Here is a workaround to #1 - make an http call directly to the stripe endpoint using Parse.Cloud.httpRequest. (I agree that Stripe.Customers.cancelSubscription in the Parse cloud module does not seem to be working)
Parse.Cloud.define("cancel", function(request, response) {
var user = request.user;
var customerStripeId = user.get("stripeId");
var key = "<stripe_api_key>"
var url = "https://api.stripe.com/v1/customers/" + customerStripeId + "/subscription"
Parse.Cloud.httpRequest({
method: 'DELETE',
params: { at_period_end: true, key: key },
url: url,
success: function() {
response.success()
},
error: function(httpResponse) {
console.error('Delete failed with response code ' + httpResponse.status);
response.failure()
}
});
});

Google search API wrapper for Node.js

I am looking for a Google search API wrapper to be used in Node.js, I have searched around but haven't found something updated and fully baked. Can anyone please recommend something working?
Thanks
Why aren't you using node client lib for Google APIs? https://github.com/google/google-api-nodejs-client
var googleapis = require('googleapis');
googleapis.discover('customsearch', 'v1').execute(function(err, client) {
// set api key
client.withApiKey('...');
client.search.cse.list({ q: '...' }).execute(console.log);
});
I'm assuming you are not referring to the deprecated Google Web Search API...
The Google Custom Search API is a RESTful API. This means that you can easily access it without a specialized wrapper.
There are a couple of modules that make this easier. The one I usually use is the request module, which lets you make HTTP requests very simply.
I just used node-google-images and it worked right away in less than 2 minutes:
https://github.com/vdemedes/node-google-images
Just call
npm install google-images
and then
client = require( 'google-images' );
client.search( 'Chicken Teriyaki', function (err, images) {
console.log(images)
});
will return
[ { width: '1920',
height: '1280',
url: 'http://www.springkitchenrestaurant.com/Chicken_Teriyaki.jpg',
writeTo: [Function] }]
(actually, it will return 4 results but stackoverflow prevents me from posting more than 2 links... - you get the gist!)
You can use jsearch module. Install with:
npm install jsearch
Usage:
js.google('queryStringYouWant',10,function(response){
console.log(response) // for Google results
})
You can use a third-party service like SerpApi with its Node.js library to scrape Google and get back structured JSON.
To install it:
npm install google-search-results-nodejs
Code example:
var gsr = require('GoogleSearchResults')
let serp = new gsr.GoogleSearchResults()
query_params = {
q: "query",
google_domain: "Google Domain",
location: "Location Requested",
device: device,
hl: "Google UI Language",
gl: "Google Country",
safe: "Safe Search Flag",
num: "Number of Results",
start: "Pagination Offset",
serp_api_key: "demo"
}
callback = function(data) {
console.log(data)
}
// Show result as JSON
serp.json(query_params, callback)
// Show results as JSON with Images
serp.jsonWithImages(query_params, callback)
// Show result as HTML file
serp.html(query_params, callback)

Resources