Firebase Functions index.ts - node.js

So I am using firebase functions, as my API request with some functions doing some work,
Right now I have 1 'index.ts' file and all of my functions inside (14 functions) there with this signature:
export const $function1 = functions.region(#region).runWith({ memory: '512MB' }).https.onRequest
export const $function2 = functions.region(#region).https.onCall(async (data, context) => {
Now my question is about organize this 'index.ts',
Some of my https requests verify token and check for valid body request,
What is the best way to organize this 'index.ts' file?
How exactly I am exporting it from files in this folder without initialize the admin sdk every time?
I am trying to make this folder organize as I can as in the future I need to add more and more functions..
Thanks for the help!

This is really a personal preference but the recommended way to organize functions by Firebase documentation is to write all your functions in their own files, export them then initialize them all in one index.ts file[1]. You can also group your functions depending on their purpose like auth or logging ...etc then export them to one index.ts file. For more info, check the documentation I have shared but as I said, you can always organize them in your own way.
[1]https://firebase.google.com/docs/functions/organize-functions

Related

GCP Cloud Functions not looking for function.js

According to GCP doc
Cloud Functions will look for files with specific names for deployable functions. For Node.js, these filenames are index.js or function.js.
Source: https://cloud.google.com/sdk/gcloud/reference/functions/deploy#--source
In my function.js file, I have:
exports.myFunction = async (req, res) => {}
And I am deploying with this command:
gcloud functions deploy myFunction --entry-point=myFunction \
--region=us-central1 --project=my-gcp-project
This causes this error
Function 'myFunction' is not defined in the provided module.
Did you specify the correct target function to execute?
Could not load the function, shutting down.
Error: function terminated. Recommended action: inspect logs for termination reason.
Curiously enough, the deployment works if I rename function.js to index.js.
Does anyone know what I might be missing here?
Following the recommended structure, you need to import all methods from relevant modules and re-export them in the index.js file so that the Virtual image can find and bind them to the appropriate functions. Without this, your functions could be simply additional code that is used in other methods as Firebase has no way to tell the difference.
I suggest checking out the following documentation:
https://firebase.google.com/docs/functions/organize-functions#write_functions_in_multiple_files

NestJS - Using DotEnv

I am working on the NestJS along with TypeOrm (MySQL).
Project itself is provisioned by Terraform, run by Jenkins and deployed on K8.
I will use process.env.******* for the DB Connection, and
when it comes to the deployment (test, stage and prod), I really don't care. Jenkins provides the credentials (provided by Terraform).
However, I want to have a local mode, where it is friendly to other developers to start the service locally.
In my previous project, I had extra file in the root. That file was only wrapper, which loads dotenv and then the main app file.
Something like this:
require('dotenv').config();
const lambdaApp = require('./index');
lambdaApp.handler()
That was simple and easy to use. I just have .env.example file, and if you need if you set it up yourself.
I figured I shall do the same with the NestJS. Unfortunately, I am stuck.
If I were to use local.index.js to start the dotenv, then How can I load and execute the main.ts file. I could call the bootstrap() function, but it wont work.
Simple approach that did not work:
require('dotenv').config();
const mainApp = require('./main.ts');
mainApp.bootstrap();
The main.ts, needs to be converted to js from ts.
I could probably find some way to do it in code, but it's looks really wrong. There has to be a simpler way to achieve this, which, unfortunately I am not seeing.
This was the case of not reading the documentation and reinventing the wheel. In my defense, I can say there are so many things to read, I don't have time. That is pure truth, but time and reading can be managed. I should have checked the official documentation first, and I would find the answer in there.
Anyway, right here it is explained. I will not post any codes
samples, since it is pointless to do it. They also use dotenv library and env file.

How do i keep a single variable(Access Token) accessed by all test suits in JEST Test?

I am new to jest testing and I am trying to find a way to access the access token for all test-suites in my project. I have tried global variable and the setup files of jest but nothing worked for me.
I tried keeping all in one describe like this answer but how can I mention only the folder name rather than file name in it?
How can I write my access token into an empty file present in my project and access that inside my test suits?
This is what I do to use common data for Jest.
Make a separate file containing whatever you need.
Then in the test file do this:
const TESTDATA = require("./test_data/auth-key.json");
Hope this helps!

Firebase Functions environment variables

So i was migrating my app from node express to firebase-functions!
In my node-express app I have .env file which contains all the data, FOr starters let's consider this as my .env file
GOOGLE_CLIENT_ID = 4046108-bssbfjohpj94l0dhpu69vpgs1ne0.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET = lTQHpj3yY57oQpO
And then in my passport strategy, I have something like this
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
userProfileURL: 'https://www.googleapis.com/oauth2/v3/userinfo',
accessType: 'offline',
passReqToCallback: true
},
Now,
Question: 1 - Firebase-functions probably don't support .env file, so can we set env variable without manually adding it using set flag? let's say I have lot variable in my environment
Question - 2: Can I access the variable I set by doing something like this
firebase functions:config:set slack.url=https://hooks.slack.com/services/XXX
using
process.env.slack.url
or we have to do (necessary)
functions.config().slack.url
Question:3 From Firebase Docs, it is written
There are environment variables that are automatically populated in
the functions runtime and in locally emulated functions, including:
process.env.GCLOUD_PROJECT: Provides the Firebase project ID
process.env.FIREBASE_CONFIG: Provides the following Firebase project
config info:
What do they mean when they mean? and if the answer to the question two is false then how are they using process.env.FIREBASE_CONFIG:
Answer for question 1:
Please note that, at this time, there doesn't appear to be a supported way to deploy true environment variables along with your function(s) using the firebase CLI tool. You can instead provide it as function.config() information, which is their recommended alternative to environment variables.
If you really really want to avoid function config, "pure" google cloud functions support setting environment variables. This page is a walkthrough of how to use a .env.yaml file and ultimately access those values from process.env in your code base. I know your file wasn't *.yaml, but this is a good solution (with some minor refactoring to YAML format).
The short version:
gcloud functions deploy FUNCTION_NAME --env-vars-file .env.yaml FLAGS
Answer for question 2
There is a difference between Firebase function config key/value pairs (i.e. function.config()) and process.env access. They are similar in purpose, but persist data in different places (i.e. in Firebase's services vs actual environment variables). Thus, the syntax for accessing each one is different.
Answer for question 3
Firebase has some process.env variables available to you by convention. They're simply documenting that for your convenience, so you can assume those are there and available as true environment variables (and not function.config() values).
Again, as of right now, the CLI tool doesn't seem to let you set true environment variables. So you'll have to go with function config, or do some other hack similar to this, which takes your function config key/values and sets them as environment variables at runtime.
const functions = require('firebase-functions');
const config = functions.config();
// Porting envs from firebase config
for (const key in config.envs){
process.env[key.toUpperCase()] = config.envs[key];
}
There's a better way as of Feb 16, 2022: Firebase now supports .env, .env.prod, .env.dev files natively!
Documentation: https://firebase.google.com/docs/functions/config-env
You can create your env files and then use firebase use dev or firebase use prod before you deploy.
These variables can be accessed via process.env.VARIABLE_NAME
Reminder
Unlike dotenv Firebase environment files should start with .env.
So, file.env will have to be named be .env.file for it to work in firebase functions.
I just had a need for this and came to a different solution than what was provided here.
First, there are a lot of discussions about why you should separate secrets from configuration. Firebase allows us to do that with the .env, .env.local, .env.dev, etc files. It is a best practice to store configuration here, not secrets.
Straight from their docs
Environment variables stored in .env files can be used for function configuration, but you should not consider them a secure way to store sensitive information such as database credentials or API keys. This is especially important if you check your .env files into source control.
What hasn't been discussed is how to store secrets. The values from the OP appear to be secrets and not configuration so in my opinion this is a relevant addition to this question.
Firebase functions have access to Cloud Secret Manager.
To help you store sensitive configuration information, Cloud Functions for Firebase integrates with Google Cloud Secret Manager. This encrypted service stores configuration values securely, while still allowing easy access from your functions when needed.
You can import runWith and defineSecret to define and access your secret.
import { runWith } from 'firebase-functions/v1';
import { defineSecret } from 'firebase-functions/params';
const secretApiKey = defineSecret('MY_API_KEY');
const functionName = runWith({ secrets: [secretApiKey] })
// ...
client.setApiKey(process.env.MY_API_KEY);
// ...
export default functionName;
This works with https functions, as well as auth, storage, and firebase triggers.
const onFirestore = runWith({ secrets: [secretApiKey] })
.firestore.document('/the/{docId}')
.onCreate(async (snap) => {
const onStorage = runWith({ secrets: [secretApiKey] })
.storage().bucket().object()
.onCreate(async (object) => {
Some note worthy caveats
The service account deploying the function needs the secret manager admin role.
Whenever you set a new value for a secret, you must redeploy all functions that reference that secret for them to pick up the latest value.
If you delete a secret, make sure that none of your deployed functions references that secret. Functions that use a secret value that has been deleted will fail silently.

Setting Firebase config inside Firebase Functions

is there a way to update configuration variables of my app within app's code?
I want to get the effect of running:
firebase functions:config:set service.client_secret='YMzPjIaVZBZKLRgGq'
in one of my functions.
I'm looking for something like this:
functions.config.allegro.refresh_token = json.refresh_token;
Thanks in advance!
This is not possible. Environment variables are effectively deployed along with your functions. Just like the code of your function can't be modified at runtime, your env vars also can't be modified. You need to redeploy your functions to get new configs.
If you need dynamic configs, consider storing them in a database instead.

Resources