cloud base functions accessing project firestore from emulator - node.js

I have a firebase project which has a project id and data in firestore. The app works great on the web, android studio, actual device etc to connect to my project firestore documents.
I want to create a cloud function so installed the firebase CLI, created a function but when i want to read data it will only access collections created at http://localhost:4000/firestore.
I have tried creating a serviceAcount from my firebase console.
const admin = require('firebase-admin');
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
I have tried using my known working firebaseConfig:
const admin = require('firebase-admin');
firebaseConfig = {
apiKey: "***************",
authDomain: "**********.firebaseapp.com",
projectId: "**********-****",
storageBucket: "*******-******.appspot.com",
messagingSenderId: "********",
appId: "1:***********:web:*************"
};
admin.initializeApp(firebaseConfig);
I have read everything (probably not) out there over the last couple days. It took me forever to even understand why the db.collection request was not returning anything, before i realized it was looking in another firestore bucket at http://localhost:4000/firestore (i created a document, and the cloud function immediately returned a working result). I thought I had figured it out.
How do i point the emulator to my existing firestore project data. I am clearly missing something really basic in understanding.

After debugging and thinking about it I realized there had to be something very basic:
firebase emulators:start --only functions
When i started the emulator with --only functions it gave me a warning that production data would be used and as thick as I am the penny dropped.
Make sure to specify --only functions which precludes the emulated firestore on localhost:4000.
It was probably so obvious no one anywhere actually stated it or what happens if you omit --only functions.

Related

Firebase Functions: Error: Client is offline

I just recently started using Firebase functions for the first time. When I was using Firebase Functions for Firestore, it worked fine but after I switched to Realtime, I've consistently been getting "Error: Client is offline".
It happens when I turn on node.js and run my application for the first time, and I .get() some data from the realtime database.
When I click on the respective line at which the error exists, it shows me this.
This is how I initialized firebase-admin:
admin.initializeApp({
projectId: <project id>,
storageBucket: <bucket url>,
credential: admin.credential.cert(serviceAccount),
databaseURL: <db url>,
});
Is it because I have the FIREBASE_CONFIG and GCLOUD PROJECT environment variables are missing error? I've seen a lot of different posts that other people are getting the same issue, but I haven't come across a proper solution.
If anyone has any solutions or if you need more information, please let me know!
I have a feeling you may be hitting a race condition in the JavaScript implementation of get(). If that is the case, you can work around it by using the once() method, which should work exactly the same in this scenario:
const _dataSnapshot = await admin.database().ref('users').child(req.body.user_uid).once();
...

Firebase - Error: 16 UNAUTHENTICATED: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid au

Hello I'm using firebase functions and I have created a Node.js project with firebase init, then I selected the options functions, firebase and storage. The project works with the firebase-admin NPM package.
When I deploy the project with firebase deploy everything goes well, but when I run the function on the cloud, it says the following message:
I have tested the entire project with the emulators and it works well.
Project Structure:
What is causing this error? Thanks!
I solved it. The problem was that I had this in the initializeApp:
const serviceAccount = require("../project-name-f3ad6ae0572f.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: BUCKET_NAME,
});
This is incorrect because I was missing the firebase configuration that is given on the Firebase Console -> Project Settings -> Your Apps.
Then, the result has to be like this:
const firebaseConfig = {
apiKey: "xxx-your-api-key-xxx",
authDomain: "project-name.firebaseapp.com",
projectId: "project-name",
storageBucket: "project-name.appspot.com",
messagingSenderId: "xxxxxxxxxxxxxxxx",
appId: "x:xxxxxxxxxxxxxxx:web:xxxxxxxxxxxxxxx",
measurementId: "G-XXXXXXXXX",
};
admin.initializeApp(firebaseConfig);
verify your pc time, i had same problem and resolving when update pc time.
import * as admin from 'firebase-admin';
const serviceAccount = require('./firebase.json');
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
}
export const firebaseDB = admin.firestore();
I might be late to this question but I faced a similar issue yesterday (16 October 2022). What I figured is that, when you set your computer's time manually, firebase doesn't work.
So your firebase timestamp rules must match with your current host time.
The code for the function framework is actually public in the GoogleCloudPlatform/functions-framework-nodejs repository (although not advertised anywhere).
In particular you can see there the cases where killInstance is used, which is the one triggering exit code 16:
const killInstance = process.exit.bind(process, 16);
These cases are (at the time of writing):
· uncaughtException
· unhandledRejection
I had the same issue today, if it's only happening in your local environment, there's a 99% chance that your computer's time is wrong.

Deploying firebase cloud function fails when I initialise firebase with a service account key

so very recently I started using google's firebase cloud functions, and loved it immediately! I very quickly restructured a project I was going to work on, and included firebase in it, so I could use the cool features of firestore, in combination with cloud functions.
Up until today, everything went on smoothly; pretty much, until I decided to play with google's FCM (Firebase Cloud Messaging) to send notifications via node js. Before this, I had created some really dense functions and already deployed to my console which were working seamlessly.
The tricky part is, at the time I created and deployed these functions, I initialised my firebase app in node js with admin.initalizeApp().
With this, everything worked fine(both locally & deployed) until I tried to use admin.messaging().sendToDevice... which resulted in a very nasty error, that basically told me I couldnt send notifications if I wasnt authenticated..
The error
(Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>
> <HEAD>
> <TITLE>Unauthorized</TITLE>
> </HEAD>
> <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
> <H1>Unauthorized</H1>
> <H2>Error 401</H2>
> </BODY>
> </HTML>
> ". Status code: 401.)
Following the error, I used a few tips from some other users on stack overflow who had faced this error, and most of them suggested that I download a service key from my console, and initialise my firebase app with admin.initializeApp({credential:admin.credential.cert(serviceAccount)})
This solution worked beautifully, as it allowed me to test my notification without seeing the above error ever again.
However, when all my tests were done, and I was ready to deploy, the new function I had just created to work on notification, as well as all my previously deployed functions could not get deployed. All of a sudden, the old working functions in my console had a red exclamation mark beside them, and I had to get rid of them. Even after I cleared out all of my console and tried to redeploy all my functions, it failed, and failed and failed with no errors(context: I wasted the whole day!!! lool!) Every tip on the internet failed for me, until I reverted back to my old way of initialising my firebase app admin.initializeApp(), then booom! all my functions uploaded successfully, and then again, the authentication error appeared again when I tried to retest my notification function.....
I guess my question is: is there anything I don't know about deploying functions to the firebase console with my app initialised with a service account key I downloaded from my console?
Is there something else I need to do to get my functions to deploy properly every time I init my firebase admin app with a service account key?? Because initialising the app with just .initalizeApp() works fine for all other purposes both locally and when deployed, except when using FCM. Can anyone please help with what is happening here??
I think it can be solved by initializing two apps and using them as objects described here. One with credentials that work for other functions and one for messaging.
If you need it only for one function you can do it even inside it. I have tested it like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
exports.first_app = functions.https.onRequest(async (req, res) => {
res.json(admin.app().name);
})
exports.other_app = functions.https.onRequest(async (req, res) => {
var otherApp = admin.initializeApp({
credential: **<< different credential here >>**
}, "2nd_app");
res.json(otherApp.name);
})
as already mentioned, you should initialize a second app just for the new function you are creating. You should put the initialization code inside the new function like this
export const saveMap = functions.https.onRequest(async (req, response) => {
const serviceAccount = require("./../serviceAccountKey.json");
admin.initializeApp({
projectId: "serviceAccount.project_id",
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your_project_id_here.firebaseio.com", //update this
storageBucket: "your_bucket_name_here.appspot.com" //update this
}, "2nd_app")
I had the same issue and once I put the second initialization code into the new function, it worked. Note that in this code the serviceAccountKey.json is in the same folder as src and lib.

Is it possible to have a Firebase Function that is triggered by changes to a Firestore that lives in a seperate Firebase project to the Function?

Let's say I have a Firebase project named "A". Within this project, I have a Cloud Firestore triggered Firebase function that needs to run when a document within Firestore changes. By default, the Firebase Function will listen to changes within Firestore on project A.
However, let's say I have a particular use case where there is a second Firebase project named "B". I need the Firebase Function within Project A to be triggered on Firestore changes that happen to Firestore within project B.
Is this possible? Firebase docs do show initializing multiple projects, which would allow me to connect to multiple databases as such:
const admin = require("firebase-admin");
const serviceAccount = require("path/to/serviceAccountKey.json");
const secondaryAppConfig = {
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
};
// Initialize another app with a different config
const secondary = firebase.initializeApp(secondaryAppConfig, "secondary");
// Retrieve the database.
const secondaryDatabase = secondary.database();
But this doesn't allow me to trigger a Firestore Triggered Firebase Function on my secondary project. Firebase functions call the firebase-functions methods directly, whereas calling a database calls the initialized project.
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('...')
.onWrite((change, context) => { /* ... */ });
Is what I would like to do possible? Or does anyone have a workaround (other than creating this Firebase Function within project B)?
It's not possible. Cloud Functions triggers can only fire in response to changes in the resources of the project where they are deployed. This is true for all types of triggers, including Firestore.
If you want code to run in response to changes in another project, the function will have to be deploy to that project.
Currently it is only possible for writes to Cloud Firestore to trigger Cloud Functions that are part of the same project. It is not possible to trigger Cloud Functions that are defined in another project.
The typical solution is for example to call a HTTP Function in the secondary project, for which you can then configure the complete URL.
I'm not sure it can be done all in one codebase - that's from a lack of experience though. I'd say, given your setup, your calling function can trigger your callee function via HTTP call (documentation)
This might require a paid Firebase plan, but I'm not certain of it (source)

Google Firebase Web App - Error involving Cloud Functions and Firestore

Recently, I tried to follow a few demos online to get started on a Google Firebase Cloud Functions Node.js server-side code for an application. Upon attempting to add a Firebase App (and Firestore with it),
const functions = require('firebase-functions');
const firebase = require('firebase-admin');
require('firebase/firestore');
var serviceAccount = require("<private key>.json");
const initAppFirebase = firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "<URL>"
});
var db = firebase.firestore();
I begin to get this one error that mentions a missing "annotations.proto" file from the google-gax module (which is apparently imported at some point in Firestore).
Error during trigger parsing: Error occurred while parsing your function
triggers.
Error: The include `google\api\annotations.proto` was not found.
at Function.GoogleProtoFilesRoot._findIncludePath
(C:\...\functions\node_modules\google-gax\lib\grpc.js:312:11)
at GoogleProtoFilesRoot.resolvePath
(C:\...\functions\node_modules\google-gax\lib\grpc.js:298:31)
...
at v1beta1 (C:\...\functions\node_modules\#google-
cloud\firestore\src\v1beta1\index.js:30:10)
at new Firestore (C:\...\functions\node_modules\#google-
cloud\firestore\src\index.js:229:18)
I have looked around on the internet, but nobody else seems to have this problem. I just reinstalled the files, but I am still getting this issue. Removing the Firestore and Firebase initializeApp code allows it to work, so I believe it has something to do with that.
Here are my module versions from package.json
"firebase-admin": "^5.12.0",
"firebase-functions": "^1.0.1",
"firestore": "^1.1.6",
Is there a way to fix this problem (botched installation, outdated libraries, missing code/requires etc.)? Thank you very much.
EDIT: Added code and package.json for version info. I dug around in the actual file \node_modules\google-gax\lib\grpc.js and found that it tries to return a valid path leading to the import file annotation.proto by trying to test google\api\annotations.proto at each parent directory.
var current = originPath;
var found = fs.existsSync(path.join(current, includePath));
while (!found && current.length > 0) {
current = current.substring(0, current.lastIndexOf(path.sep));
found = fs.existsSync(path.join(current, includePath));
}
if (!found) {
throw new Error('The include `' + includePath + '` was not found.');
}
return path.join(current, includePath);
There is, unfortunately, no such directory, though perhaps it is looking for the annotations file in google-proto-files\google\api\annotations.proto (but adding that file in manually leads to further errors). There is also a github issue here https://github.com/googleapis/nodejs-firestore/issues/175 mentioning it.
You say that you're trying to build a web app. But the code you are using is for initializing the Firebase Admin SDK in a (server-side) Node.js script.
If you want to use Firestore in your web app, start with the code you see when you click the WEB tab on this page:
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase-firestore.js"></script>
And then:
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});
// Initialize Cloud Firestore through Firebase
var db = firebase.firestore();
You can get the values in that initializeApp call by:
Going to the Project overview page
Click ADD ANOTHER APP
Click Add Firebase to your web app

Resources