How to get Firebase Project Name or ID from Cloud Function - javascript

I am using Cloud Functions and want to get the project name from within one of my Javascript server files. I know that value is stored in the .firebaserc, but I don't think that file is available on the server, right? I want to do something like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.getProjectName(); // or getProjectID()
or
functions.getProjectName();

Thank you #Frank. The answer is:
process.env.GCLOUD_PROJECT.
I'm not sure where the variable process comes from, but this does work to get the project name.

Firebase admin SDK has access to that information for you.
const admin = require('firebase-admin');
const projectId = admin.instanceId().app.options.projectId

This worked for me. (node 10)
const FIREBASE_CONFIG = process.env.FIREBASE_CONFIG && JSON.parse(process.env.FIREBASE_CONFIG);
const projectId = FIREBASE_CONFIG.projectId;

try this :
const projectId = admin.instanceId().app['options_'].credential.projectId

For cloud functions running on newer versions of Node:
import firestore from "#google-cloud/firestore";
const client = new firestore.v1.FirestoreAdminClient();
const projectId = await client.getProjectId();

From the Firebase docs:
process.env.FIREBASE_CONFIG: Provides the following Firebase project config info:
{
databaseURL: 'https://databaseName.firebaseio.com',
storageBucket: 'projectId.appspot.com',
projectId: 'projectId'
}
Note that since it's a JSON string you need to parse it like this:
const projectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
Alternatively you could use the undocumented firebaseConfig() method from the firebase-functions package in your Cloud Functions, like so:
import { firebaseConfig } from "firebase-functions";
const projectId = firebaseConfig().projectId;
Additionally, Google Cloud Platform (which Firebase runs on top of) will automatically populate the environment variables documented here, depending on which runtime you're using.

The way to retrieve the project ID using admin SDK is
admin.appCheck().app.options.credential.projectId
This also works in headless setups like Docker where the environment variable GOOGLE_APPLICATION_CREDENTIALS is set.

Currently I'm using app.INTERNAL.credential_.projectId.
This is clearly not save, but so far there is no cohesive way to get it (AFAIK)

This is a combination of the answers given above:
function getProjectID() {
return firebaseInstance.options.projectId ||
(firebaseInstance.options.credential && firebaseInstance.options.credential.projectId) || '';
}
Or in TypeScript:
function getProjectID(): string {
return firebaseInstance.options.projectId ||
(firebaseInstance.options.credential && (firebaseInstance.options.credential as unknown as { projectId: string }).projectId) || '';
}

You can use functions.config().firebase.projectId
PS the easiest way to initialize app is admin.initializeApp(functions.config().firebase);

Related

How to set environment variables like test environment for playwright-cucumber js

I've been using Playwright with Cucumber for e2e-automation of a react web application. This repo has been my starting point and it's been working out pretty good.
However, I'm looking for pointers on how to run these tests on different test environments - like development or QA, so that the target urls and other params vary as per the environment passed. For eg -
if (env == dev){
baseurl = dev_url
}
else{
baseurl = qa_url
}
The Cucumber documentation mentions the World parameter - an this issue looks like a similar issue, however I'm skeptical of passing a different JSON for this task.
Can this be achieved only at a Cucumber level or is there a Playwright or Node way of doing this?
As you are already using cucumber, define your world file like this:
First you can segregate your properties files into: properties-dev.json and properties-qa.json. Below code reads properties file based on env we are passing in defaultOptions object and stores entire properties file data into 'this'. Use 'this' in your hooks file and call this.keyNameForUrl to get url specific to environment.
Note: 'this' can be accessible only in world and hooks files (refer // https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md). If you need this data in other files, create a separate class and declare all public static varibles in it. In Hooks BeforeAll function, reassign values from 'this' to the static variables created in the class.
import { setWorldConstructor } from 'cucumber';
const fs = require('fs');
const defaultOptions = {
env: 'qa'
};
function processOptions(options) {
let envFile = 'properties-' + options.env + '.json';
let environment = JSON.parse(fs.readFileSync(envFile));
return Object.assign(options, environment);
}
function World(input) {
this.World = input;
});
Object.assign(this, processOptions(Object.assign(defaultOptions, options)), options);
}
setWorldConstructor(World);
// https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/world.md

typescript, how to reference the unexported OAuth2Client? google-api-nodejs-client

I am trying to follow https://developers.google.com/sheets/api/quickstart/nodejs tutorial
I am using typescript and I like the type annotation and auto-complition features it provides and I would like to re-write the example in typescript and async rather than callbacks.
Sadly I am stuck, OAuth2Client.
in my code I creating an oauth client inside a function like this:
async function setupClient() {
const content: string = await fs.readFile("credentials.json", "utf8");
const credentials = JSON.parse(content);
// eslint-disable-next-line camelcase
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client: o2 = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
type OAuth2Client = typeof oAuth2Client;
return oAuth2Client;
}
And I would like to delegate that client to two other setup functions:
function setupAuthUrl(oAuth2Client, scopes) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: scopes,
});
return authUrl;
}
function setupToken(oAuth2Client, code) {
//code
}
But I am struggling to annotate oauth2client type as it is not directly exposed by anything?
One would guess that it is exposed under the 'oauth2_v2' namespace? but doesn't seem to be it.
I have been looking for a way to reference this type prior to instantiation, preferably via importing, sadly, when installing this libary via npm install googleapis it doesn't provide a dependency to niether of these google-auth-library, googleapis-common where it is exported and exposed for importing. eslint errors unless it adds the dependency and I struggle to see why It is required as the type should be accessable for code completion with ease.
As for type aliasing:
type OAuth2Client = typeof GoogleApis.prototype.auth.OAuth2.prototype;
This is the only option I could figure out that doesn't throw an error/warning(object as namespace) for aliasing. this is both a long line and very weird one at that too coming from other OO languages
TLDR: What's the prefered way to access OAuth2Client and maybe other types for code completion in typescript?
As of Jun 19 a merge request adding this feature has been approved.
https://github.com/googleapis/google-api-nodejs-client/issues/2208
import { google, Auth } from 'googleapis';
const oauthClient: Auth.OAuth2Client = new google.auth.OAuth2();
Thanks for angelxmoreno for the example

the first try to firebase cloud functions

I am trying to make my first firebase cloud function.
I want to add the value of name field -which is in 'amr' document -inside ahmed document with the field name newName . I made this function but each time it gives an error or don't show anything
what is the problem in my function
const functions = require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp();
exports.myfunc=functions.firestore.document('Users/amr').onWrite((change,context)=>{
const name=change.data().name;
return admin.firestore().document('Users/ahmed').add({newName:name});
});
Change this:
const name=change.data().name;
into this:
const name=change.after.data().name;
to be able to retrieve the data after the write
more info here:
https://firebase.google.com/docs/functions/beta-v1-diff#cloud-firestore
also change
return admin.firestore().document('Users/ahmed').add({newName:name});
to
return admin.firestore().doc('Users/ahmed').add({newName:name});

Firebase function .onWrite not working?

Ok, I have looked at similar questions like Firebase function onWrite not being called and thought it was my fault getting the reference, but I have no idea what is happening here with my Firebase functions.
I am just trying to get a function to write to my database when a write has been made to database. I followed the firebase tutorial exactly:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
//https://firebase.google.com/docs/functions/database-events
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// const gl = require('getlocation');
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
exports.enterLocation = functions.database.ref('/Users/{name}') //brackets is client param
.onWrite(event => {
// Grab the current value of what was written to the Realtime Database.
// const original = event.data.val();
console.log('SKYLAR HERE:', event.params.name);
// You must return a Promise when performing asynchronous tasks inside a Functions such as
return firebase.database().ref('/Users/{name}').set({ location: 'test loc' });
});
The function is being run, yet in my logs I get a pretty unhelpful error that it is getting the {name} param, and data is definitely written to my database, however my SERVER code is not writing:
I get -
ReferenceError: firebase is not defined at
exports.enterLocation.functions.database.ref
Which makes no sense as it is defined. I just want to add an extra child under the user I create, like I do already with "password"
What am I doing wrong?
Two problems here. First, you haven't defined firebase anywhere in your code. I think you meant to use admin instead to use the Admin SDK.
Second, it looks like you're trying to do variable interpolation into a string to build the name of the ref. Your syntax is wrong here.
I imagine you're trying to say this instead in your last line of code:
return admin.database().ref(`/Users/${name}`).set({ location: 'test loc' });
Note the backticks on the string quotes. That JavaScript syntax lets you use ${exp} to insert the contents of some expression in the string.
It turns out you don't even need to use the admin SDK here. Since you're trying to write back to the same location that triggered the function, you can just use the ref that comes from the event object:
return event.data.adminRef.set({ location: 'test loc' });
instead of this:
return firebase.database().ref('/Users/{name}').set({ location: 'test loc' });
use this:
return admin.database().ref('/Users/{name}').set({ location: 'test loc' });

Express - Passing mysql connection to scripts

I defined mysql connection with all parameters necessary to app.js, how can make visible to other scripts in routes/ by default, without requiring or redefining mysql parameters, just using client.query(..)?
A pattern I use is to set up my db object in a module once and export it: (let's call it utils/mySQL.js)
//I haven't used real mysql in node so excuse the pseudo-syntax:
var db = require('mysql-driver-thingy');
db.connect('localhost', 'sqlport', options...);
db.otherSetupFunctions();
console.log("Finished db setup. You should only see this message once! Cool.");
module.exports = db;
And then I can require the db object everywhere I need it. Since requires are cached, this does't actually call the setup methods multiple times.
In app.js:
var db = require('./utils/mySQL.js');
...
In models/user.js:
var db = require('../utils/mySQL.js');
...
A final option, which isn't recommended, is to pollute the global namespace. This seems to be the answer you're really after:
//set up your db
...
// and now make it available everywhere:
global.client = db.client
You can now magically use the client object in all your modules, without even requiring it.
There are many reasons globals are bad, though:
If your code and other code define globals, they could conflict and overwrite each other.
It's hard to find where you defined the db/client object, etc.
You can inject mysql connection into other scripts like this:
app.js
var mysqlConnection = new Conection(params);
require('controller/main.js)(mysqlConnection);
main.js
module.exports = function(mysqlConnection) {
// You can access your mysql connection here
};
UPDATE:
You can inject several variables same way. Also you still can export methods from module if you need this:
app.js
var mysqlConnection = new Conection(params);
var news = require('model/news.js)(app, mysqlConnection);
news.list(function(err, news) {
// Do something
});
news.js
module.exports = function(app, mysqlConnection) {
var methods = {};
// mysql connection and app available from here
methods.list = function(cb) {
mysqlConnection.list(function(err, data) {
cb(err, data);
});
};
return methods;
};

Categories

Resources