how to use firebase https trigger functions - node.js

I'm creating a token generator using firebase cloud functions and I wanted to use an https trigger to create the token, however I need to include data within the call to the url. I know it is possible but I don't necessarily know how to do it.
I need this so I can set values for certain variables in my function.
So the final url might look something like this in pseudo code:
https://tokengen/identity=/room=
here, identity and room are the two values I want to include for the variales for when calling the function.
so to reiterate,
I know you can request data using:
exports.token = functions.https.onRequest((request, response) => {
but how do I include data along with the https call to include as variables. An example would be greatly appreciated. As would any answers, suggestions, or references.
EDIT:
here's the updated code,
exports.tokenGenerator = functions.https.onRequest((request, response) => {
const { identity, roomName } = request.query;
const AccessToken = require('twilio').jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
const twilioAccountSid = '1xxxxxxxxxx';
const twilioApiKey = '1xxxxxxxxxx';
const twilioApiSecret = '1xxxxxxxxxx';
function generateToken(identity, roomName) {
const videoGrant = new VideoGrant({
room: roomName
});
const token = new AccessToken(twilioAccountSid, twilioApiKey, twilioApiSecret);
token.addGrant(videoGrant);
token.identity = identity;
return token.toJwt();
}
response.send(token.toJwt());
});
when I use the url it returns Error: could not handle the request

You can do something like this -
https://yourFB.cloudfunctions.net/token?identity=12&room=12
and you can use it like -
exports.token = functions.https.onRequest((request, response) => {
const { identity, room } = request.query;
...
});
Hope this helps.

Related

How to parse XML feed URL and store items in Firestore using cloud functions?

I have been given an assignment to fetch a JSON API, and also parse an XML feed URL and store their responses inside separate Firestore collections. I am not really good at cloud functions, but after lots of research, I have written the cloud function code below for the JSON API and it works well.
const functions = require("firebase-functions");
const axios = require("axios");
const admin = require("firebase-admin");
const api_token = "XXXXXXX";
const includes = "XXXXXX";
const url = "https://XXXXXXXXXXXXXX.com/?api_token=" + api_token + includes;
exports.allLeagues = functions.region('europe-west1').https.onRequest(async (req, res) => {
try {
let response = await axios.get(url);
var data = response.data.data;
for (let leagueData of data) {
await admin.firestore().collection("leagues").doc(leagueData.id.toString()).collection("all_data").doc(leagueData.id.toString()).set({
id : leagueData.id,
name : leagueData.name,
logo_path : leagueData.logo_path,
is_cup : leagueData.is_cup
});
}
console.log("Table complete...");
console.log("successful");
return res.status(200).json({ message: "successful" });
} catch(error) {
console.log("Error encountered: "+error);
return res.status(500).json({ error });
}
});
I am through with the JSON API. But for the XML feed, I don't know where to start. I have done lots of research to no avail. I found this on Stackoverflow but it doesn't address my need. Assuming this is my feed: https://www.feedforall.com/sample.xml , please how do I parse it and save the items inside Firestore?
Kindly help.
Thank you.
You can use rss-parser that can be used to fetch data from RSS feeds or parse from XML strings as shown below:
// npm install rss-parser
const Parser = require("rss-parser");
const parser = new Parser();
exports.rssFeedParser = functions.https.onRequest(
async (request, response) => {
const rssUrl = "https://www.feedforall.com/sample.xml";
const feed = await parser.parseURL(rssUrl);
const { items } = feed;
const batch = db.batch();
items.forEach((item) => {
const docRef = db.collection("rss").doc();
// restructure item if needed
batch.set(docRef, item);
});
await batch.commit();
response.send("Done");
}
);
Do note that you can add up to 500 documents only using Batched Writes as in the answer above. If your feed can return more than that, then you should create multiple batches of 500 or add them individually.

Access API data with Firebase Functions

I'm trying to pull data from an API and store it in a variable.
I'm using firebase functions, IEXCloud and node.js, but I can't access the data in the body.
The link works when I use it on its own and if I remove .body from the link, then the link is send to the browser.
This is what I have:
const functions = require("firebase-functions");
const sA = "https://sandbox.iexapis.com/stable/";
const key = "(API-Key)";
exports.symbol = functions.https.onRequest((request, response) => {
const symbol = (`${sA}stock/aapl/quote?token=${key}`).body;
response.send(symbol);
});
You're not calling any API here const symbol = (${sA}stock/aapl/quote?token=${key}).body;.
Did you mean to call fetch():
exports.symbol = functions.https.onRequest((request, response) => {
return fetch(`${sA}stock/aapl/quote?token=${key}`).then((res) => {
symbol = res.body;
response.send(symbol);
});
});

Firebase Functions extracting Token

Trying to grab my FCM token from my Cloud Firestore using Firebase Function
my function code:
const functions = require("firebase-functions");
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotificationToFCMToken = functions.firestore.document('Posts/{likes}').onWrite(async (event) => {
const title = event.after.get('title');
const content = event.after.get('likes');
let userDoc = await admin.firestore().doc('Users').get();
let fcmToken = userDoc.get('{token}');
var message = {
notification: {
title: title,
body: "you have a new like",
},
token: fcmToken,
}
let response = await admin.messaging().send(message);
console.log(response);
});
My Firestore
Posts:
Users:
if I manually add the token everything works but just send every "like" to one device, my goal is to send a link to only the owner of the post
It's probably more alike this:
let userRef = event.after.get('ref'); // obviously the path is mandatory ...
let userDoc = await admin.firestore().doc(userRef).get(); // then this should match
let token = userDoc.get('token'); // and the token should be accessible
Add logging to see what you get: functions.logger.info('🞬🞬🞬 ' + JSON.stringify(event)); ...viewable at https://console.cloud.google.com/logs/query. When listening for Posts/{likes} you'd likely need an additional query - and when listening for Posts, you'd need to determine changes. Getting access to ref is required to make the subsequent query work.
Martin's answer is correct, but it seems that the ref field is of type Reference, see the slash at the beginning, plus the error you get.
So, if this assumption is correct, you should use the path property, as follows (adapting Martin's code):
let userRef = event.after.get('ref'); // obviously the path is mandatory ...
let userDoc = await admin.firestore().doc(userRef.path).get(); // then this should match
let token = userDoc.get('token'); // and the token should be accessible
In addition, in order to correctly manage the life cycle of your Cloud Function, you should do, at the end:
let response = await admin.messaging().send(message);
console.log(response);
return null;
or simply
return admin.messaging().send(message);

Access azure billing API

I would like to create a dashboard with graphs about costs of my azure resources (as detailed as possible). Meaning, a list of monthly invoices is not enough (but I would already be very happy if I a could achieve that!!)
Anyway, the first thing I noticed is that if you find an example the endpoint urls look like this
https://management.azure.com/subscriptions/${subscriptionId}/resourcegroups?api-version=2016-09-01
Check the end of the url 2016-09-01, doesn't look very up2date. This medium post was the best article I could find, but it also uses these urls.
Furthermore, I was not able to follow the steps described, first it uses postman to retrieve an access_token (not very useful for me because I need it automated) and second, somewhere in the middle an access_token is retrieved but never used.
So, I found a npm packages like [azure-arm-billing][2] from which I was able to write the following program (mostly copy-paste):
const msRestAzure = require('ms-rest-azure');
const BillingManagement = require('azure-arm-billing')
const clientId = process.env['CLIENT_ID'];
const secret = process.env['APPLICATION_SECRET'];
const domain = process.env['DOMAIN'];
const subscriptionId = process.env['AZURE_SUBSCRIPTION_ID'];
// Retrieve access_token
const app = new msRestAzure.ApplicationTokenCredentials(clientId, domain, secret);
app.getToken((err, token) => {
console.log(token.accessToken);
});
// =======
msRestAzure
.interactiveLogin( { domain }) // The argument here is nowhere documented
.then(credentials => {
console.log(credentials);
let client = new BillingManagement(credentials, subscriptionId);
return client.invoices.list();
})
.then(invoices => {
console.log('List of invoices:');
console.dir(invoices, { depth: null, colors: true });
});
Running this shows a nice access_token and invoices
...
List of invoices:
[
{
id: '/subscriptions/../providers/Microsoft.Billing/invoices/....',
name: '...',
type: 'Microsoft.Billing/invoices',
invoicePeriodStartDate: 2019-08-25T00:00:00.000Z,
invoicePeriodEndDate: 2019-09-24T00:00:00.000Z,
billingPeriodIds: [
'/subscriptions/.../pr..s/Micro..ing/bill..ods/201910-1'
]
},
{
id: '/subscriptions/9ea...3d/providers/Microsoft.Billing/invoices/201909-...',
name: '....',
type: 'Microsoft.Billing/invoices',
invoicePeriodStartDate: 2019-07-25T00:00:00.000Z,
invoicePeriodEndDate: 2019-08-24T00:00:00.000Z,
billingPeriodIds: [
'/subscriptions/..../providers/Microsoft.Billing/billingPeriods/201909-1...'
]
}
]
Although I have my invoices, there are no numbers. And I would like to retrieve costs for every resources.
So the documentation seems to be outdated up to not existing for what I want (as it seems). My question is if someone was able to retrieve information like this? I would really like to know how!!
UPDATE
It seems to be a permission issue. So, below I share some screenshots showing what I have right now. Maybe from these it is clear what I miss or have setup incorrectly. So first, here is my latest nodejs app:
const msRestAzure = require("ms-rest-azure");
const ConsumptionManagementClient = require("azure-arm-consumption");
const clientId = '76d79....'; // App registration ID
const secret = '****...'; // App registration secret
const domain = 'dc36...'; // tenantId
const subscriptionId = '9ea2d...'; // subscription ID
const AzureServiceClient = msRestAzure.AzureServiceClient;
//an example to list resource groups in a subscription
msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain).then((creds) => {
const client = new ConsumptionManagementClient(creds, subscriptionId);
const expand = '';
const filter = '';
const skiptoken = '';
const top = 1000;
const apply = '';
return client.usageDetails.list(expand, filter, skiptoken, top, apply).then(result => {
console.log('The result is:', result);
});
}).catch((err) => {
console.log('An error occurred:');
console.dir(err, { depth: null, colors: true });
});
Which outputs a statusCode 401
Error: Unauthorized. Request ID: e6b127...
...
So, I have in AD an App registration
Its API permissions are
Finally, I have just one subscription
With the following IAM settings
Any suspicious?
If you're looking for resource costs, I would suggest that you take a look at Consumption API - List Usage Details. That will give you the consumption for all the resources.
You will need to install azure-arm-consumption package.
Here's the sample code:
const msRestAzure = require("ms-rest-azure");
const ConsumptionManagementClient = require("azure-arm-consumption");
msRestAzure.interactiveLogin().then((creds) => {
const subscriptionId = "<your subscription id>";
const client = new ConsumptionManagementClient(creds, subscriptionId);
const expand = "";
const filter = "";
const skiptoken = "";
const top = 1000;
const apply = "";
return client.usageDetails.list(expand, filter, skiptoken, top, apply).then((result) => {
console.log("The result is:");
console.log(result);
});
}).catch((err) => {
console.log('An error occurred:');
console.dir(err, {depth: null, colors: true});
});
This is taken from here: https://github.com/Azure/azure-sdk-for-node/tree/master/lib/services/consumptionManagement.

Firebase database querying taking to much time in Cloud Function

I use nodejs as a backend hosted on the firebase functions to query my firebase database, I have this code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});
admin.initializeApp(functions.config().firebase);
const express = require('express')
exports.getAjax = functions.https.onRequest((request, response) => {
cors(request, response, () => {
console.log("request.body :", JSON.stringify(request.body));
console.log("request.query :", JSON.stringify(request.query));
var date = {
startDate: request.body.startDate,
endDate: request.body.endDate
}
var db = admin.database();
var logsDbPath = 'logs';
var usersDbPath = 'users';
var ref = db.ref(logsDbPath);
var tags;
db.ref(usersDbPath).once('value').then(function(tagsSnapshot) {
tagsSnapshot.forEach(function(tagSnapshot) {
var tagId = tagSnapshot.key;
tagSnapshot.forEach(function(sessSnapshot) {
var userSessId = sessSnapshot.key;
var userInfo = sessSnapshot.val();
});
});
tags = JSON.parse(JSON.stringify(tagsSnapshot.val()));
console.log(tags);
});
});
});
My main problem is that console.log(tags); and actually finishing the query and get the value for tags took ~38 sec in this case (sometimes takes ~ 1 min), I will put picture bellow:
And that object it's not that big at all, like 100 rows with 4 properties each, I don't think it should take that much, probably I did something wrong, but where?, I also have to write a promise or a callback in order to send that tags var response on the front end, cause the function finish before I get any value on tags(see picture), I come from a PHP background and this asynchronous javascript concept it's quite new for me.
You're not sending any response back to the client, which means that the function will keep running until it times out.
To make sure the function runs only for as long as needed, send a response to the client when you've loaded the data:
exports.getAjax = functions.https.onRequest((request, response) => {
cors(request, response, () => {
console.log("request.body :", JSON.stringify(request.body));
console.log("request.query :", JSON.stringify(request.query));
var date = {
startDate: request.body.startDate,
endDate: request.body.endDate
}
var db = admin.database();
var logsDbPath = 'logs';
var usersDbPath = 'users';
var ref = db.ref(logsDbPath);
var tags;
db.ref(usersDbPath).once('value').then(function(tagsSnapshot) {
tagsSnapshot.forEach(function(tagSnapshot) {
var tagId = tagSnapshot.key;
tagSnapshot.forEach(function(sessSnapshot) {
var userSessId = sessSnapshot.key;
var userInfo = sessSnapshot.val();
});
});
tags = JSON.parse(JSON.stringify(tagsSnapshot.val()));
console.log(tags);
// Send the response to the client, which also ends the function
response.status(200).send(tags);
});
});
});
Aside from that it's hard to say much. Keep in mind that Cloud Functions is in beta and is constantly changing, we have no way of knowing whether this is a cold start or warm start, and we can't see your project to inspect what's going on.
If you'd like to have more help here, I recommend that you try to reproduce the problem in a more troubleshoot-friendly environment. For example, can you reproduce the perfor,ance problem with a local node.js process?

Resources