How to properly Organize Firebase Functions in Groups? - node.js

I am following This Guide to create a Functions project with multiple function files in NodeJS. while this is a good base, it does not show how to properly initiate a firebase app by using const app = admin.initializeApp() in a way that could be reused across the different files. my initial thought was to add the following in index.ts and import app as needed, but this raises a Maximum call stack size exceeded error.
import admin = require('firebase-admin');
export const app = admin.initializeApp();
While searching online I could only find some older posts that don't apply to current versions. can anyone provide a guideline for this?

This looks like a circular dependency issue. You need to initialize Firebase Admin only once at the beginning of index.ts and import other services as needed in other files as shown below:
// index.ts
// Don't export anything from this file.
import { initializeApp } from "firebase-admin/app";
initializeApp({
databaseURL: "<DB_URL>",
storageBucket: "<BUCKET>.appspot.com",
});
export * from "./metric";
// metric.ts
import { https } from "firebase-functions/v1";
import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore();
export const test = https.onRequest(async (req, res) => {
const metricData = await db.collection("metrics").get();
res.json(metricData.docs.map((doc) => doc.data()));
});

Related

How to use Firebase Cloud Functions with the new modular Firestore API?

I have upgraded my Firebase v8 project to v9. The web application now uses the modular SDK with the new functional API for Firestore.
In this project I use Firebase Functions. There I have upgraded to firebase-admin 11.0.0. But it seams it does not provide the new functional API for Firestore.
const { initializeApp } = require('firebase-admin/app');
const app = initializeApp();
import { getFirestore } from "firebase/firestore";
const db = getFirestore(app);
This throws:
TypeError: Cannot read properties of undefined (reading 'getProvider')
at Object._getProvider (/p/happygast/node_modules/#firebase/app/src/internal.ts:110:6)
at Object.getFirestore (/p/happygast/node_modules/#firebase/firestore/src/api/database.ts:185:10)
Now I am not sure if I am doing something wrong? Or is there no functional Firestore API for Cloud Functions?
In essence: Is firebase-admin/app compatible with firebase/firestore? Or: How do I initialize and use firebase/firestore in Firebase Cloud Functions?
You are importing initializeApp() from the Firebase Admin SDK but getFirestore() from the Firebase Client SDK and then passing an instance of Admin SDK in it that's invalid. Instead, you should import Firestore from the Admin SDK itself as shown below:
const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore'); // not firebase/firestore
// Initialize by ADC or another service account
const app = initializeApp();
const db = getFirestore(app);
If you want to use the client SDK, then you'll have to initialise the Firebase instance using the client SDK itself:
const { initializeApp } = require('firebase/app');
const { getFirestore } = require('firebase/firestore');
// use the web config that can be found in Firebase console
const clientApp = initializeApp({ ...config });
cpmst db = getFirestore(clientApp);

How to access admin firestore using firebase admin SDK?

I am working on an application, where it uses Next.js and Firebase.
I need to implement server-side authentication. Firebase allows connecting the server using Firebase Admin SDK.
const admin = require("firebase-admin");
const serviceAccount = require("../../../../3-firebase/service-account-key/service-account-file.json");
try {
admin.initializeApp({
credential: admin.credential.cert({
client_email: process.env.FIREBASE_CLIENT_EMAIL,
private_key: process.env.FIREBASE_PRIVATE_KEY,
project_id: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
}),
});
console.log("Initialized.");
} catch (error) {
if (!/already exists/u.test(error.message)) {
console.error("Firebase admin initialization error", error.stack);
}
}
const db = admin.firestore();
export { db };
I installed the firebase-admin package using NPM and I setup firebase admin SDK using the above code by creating a separate file called "firebase-admin.js"
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
};
const defaultApp = initializeApp(firebaseConfig);
export default defaultApp;
The above code is the default firebase application setup in a separate file called "firebase.js"
The problem I encountered is I am not able to access the admin firestore. However, I can able to access the default firestore.
What I observed is admin SDK is able to initialize using the credentials (private key). But I don't know why I can't access admin firestore. I mean when i use admin firestore the console gives error of 500 (internal server error)
Here is the error message, when I try to use admin.firestore()
{"error":{"code":"invalid-argument","name":"FirebaseError"}}
versions I am using
"firebase": "^9.6.6",
"firebase-admin": "^10.0.2",
Timely help is much needed
You're importing the initializeApp method from the Firebase Javascript SDK. You should be importing from the Firebase Admin SDK.
import { initializeApp } from "firebase/app";
vs.
import { initializeApp } from "firebase-admin/app";
Using firebase-admin v10.0.2 I was able to successfully access the db adding this in my config.js file, similar to your firebase.js file.
const ServiceAccount = require('../superSecretServiceKeyFile.json');
const app = initializeApp(ServiceAccount);
const { getFirestore } = require('firebase-admin/firestore');
const db = getFirestore(app);

how to initialize firebase admin SDK in nodejs

I am try to initialize firebase admin SDK in my project but it is not working. I intend using it in my next js API for admin backend
import {
initializeApp,
applicationDefault,
cert,
} from "firebase-admin/app";
import {
getFirestore,
Timestamp,
FieldValue,
} from "firebase-admin/firestore";
import serviceAccount from "../secret.json";
const app = initializeApp({
credential: cert(serviceAccount),
});
export default app.getFirestore();

Firebase database isn't starting

I am a newbie in JavaScript. Recently I have installed firebase admin and kept the code in global scope, database.js. Like this.
import app from 'firebase-admin';
import firebase_key from './firebase_key.js';
app.initializeApp({
credential: app.credential.cert(firebase_key),
databaseURL: "https://study-boss-681fa-default-rtdb.firebaseio.com"
});
console.log('database started');
export default app.database();
Now I want to access this database from my service class. My serice class is
import { getDatabase} from "firebase-admin/database";
const database = getDatabase();
This service class code is throwing the following error.
FirebaseAppError: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.
If you are just using getDatabase() directly then there's a high chance that it's being access before your initializeApp is executed. I would recommend initializing all Firebase services in a single file and importing them wherever required as shown below:
import { initializeApp } from 'firebase-admin/app';
import { getDatabase } from 'firebase-admin/database';
import firebase_key from './firebase_key.js';
const app = initializeApp({
credential: app.credential.cert(firebase_key),
databaseURL: "https://study-boss-681fa-default-rtdb.firebaseio.com"
});
const database = getDatabase(app);
console.log('database started');
export { database };
Now you can import { database } from "..path/to/firebase.js" wherever required.

Module not found: Can't resolve 'fs' on #google-cloud/storage

Getting the Module not found: Can't resolve 'fs' error when trying to list out buckets from GCP Storage.
import { Storage } from '#google-cloud/storage';
const googleCloud = new Storage({
keyFilename: '../../my-project-c1a44bf80be3.json',
projectId: 'my-project',
});
googleCloud.getBuckets().then((x: any) => console.log(x));
my-project-c1a44bf80be3.json (Download from GCP) exists and is the project level
Error:
event - compiled successfully
event - build page: /
wait - compiling...
error - ./node_modules/#google-cloud/storage/build/src/file.js:24:0
Module not found: Can't resolve 'fs'
null
Could not find files for / in .next/build-manifest.json
event - compiled successfully
The same error appears when using googleapis.
However, instead of ./node_modules/#google-cloud/storage/build/src/file.js:24:0 it's in the google-auth-library module that comes with the googleapis.
Added using yarn.
This usually happens when you import or reference firebase-admin in the client side, check your code for wrong imports where you might be calling
import * as firebase from "firebase-admin";
instead of
import firebase from "firebase";
I faced the same problem but this guide was the solution in my case.
As mentioned before, the problem is that the firebase-admin package is designed to run in a NodeJs environment and not on the client. Extending webpack.config.js or next.config.js with certain entries did not solve the problem for me.
I have noticed your are using NextJS. So the solution is to move the firebase-admin calls to the NextJS API which you can create within the /pages/api folder.
Here is a simple example to fetch user data from the client.
You need:
/src/lib/firebase.ts: firebase initialization
/src/pages/api/user.ts: NextJS API handler
/src/components/xyz.tsx: component on client, which calls the API
// /src/lib/firebase.ts
import admin from "firebase-admin";
import { cert } from "firebase-admin/app";
import certConfig from "./firebase-adminsdk-config.json"
admin.initializeApp({
credential: cert(certConfig)
});
console.log("Firebase initialized.");
export default admin;
// /src/pages/api/user.ts
import admin from 'lib/firebase'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const firebase = admin.firestore()
const collection = firebase.collection('users')
// get any data from requests body
const { user } = req.body
// perform your firebase collection call
const data = await collection.get(user.id)
// return data to client
res.status(200)
res.json({
success: true,
result: data
});
return res
}
On the client side then you just have to perform a GET to your own API
// /src/components/xyz.tsx
...
const onLogin = async (user) => {
const response = await fetch(`/api/users`, {
method: "GET",
body: JSON.stringify({ user }),
});
// data => { success: boolean, result: any }
const data = await response.json();
return data;
}
...
Posting the solution provided in the comments for visibility.
In your webpack configuration, you can indicate that certain modules
like fs should be stubbed out; at which point you should be able to
run this library client-side. For example:
node: {
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
...config.node,
fs: 'empty',
child_process : 'empty',
net : 'empty',
tls: 'empty',
}
The scenario you are describing is now being handled by Google. Although there is no ETA, the issue is being prioritized.

Resources