I've a deployed a callable function, say foo, using
firebase deploy --only functions:foo
and I'm calling it in Flutter using:
var result = await FirebaseFunctions.instance.httpsCallable('foo')();
var data = result.data;
All good. But I'd like to run this function in the Firebase Emulator. When I run
firebase emulators:start --only functions
I can see the emulator up and running, and I'm connecting my Flutter app to the emulator using:
FirebaseFunctions.instance.useFunctionsEmulator('localhost', 4000);
However, I don't know how to invoke the callable foo in Flutter using the Firebase Emulator. I saw this related thread but it doesn't really answer my question.
EDIT:
Here's the console output:
✔ functions[us-central1-foo]: http function initialized (http://localhost:5001/my_project/us-central1/foo).
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000 │
└─────────────────────────────────────────────────────────────┘
┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
├───────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
└───────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at localhost:4400
Other reserved ports: 4500
I tried
useFunctionsEmulator('localhost', 4000);
useFunctionsEmulator('localhost', 5001);
but both of them throw the following error on calling httpsCallable('foo') but without the emulators, this function does work.
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: [firebase_functions/unavailable] UNAVAILABLE
I suspect your host and port values might be incorrect.
When you start up your emulator, the logs will display all the ports that are being used for your various emulators. There's also the firebase.json file that has the port configurations for the emulators.
Also, localhost is not automatically identified by the clients. For Android you might have to configure networkSecurityConfig in your manifest by creating a network security config xml. For iOS, I think there should be something that needs to be added in the plist file - has to be checked confirmed.
Once your clients are able to access localhost (implicitly or explicitly), you can connect to your emulated functions. For example, I have explicitly state the host value in my code (this is not expected to change across restarts).
Here is the code that I use in Kotlin:
functions = FirebaseFunctions.getInstance()
/*
* Emulator
* */
if (emulatorMode) { //Local Testing
functions.useEmulator("10.0.2.2", 5001)
} else { //Live
functions = Firebase.functions
}
// Call the function and extract the operation from the result
return functions
.getHttpsCallable(function)
.call(inputData)
.continueWith { task ->...
It doesn't seem like a port or setup issue to me. Your console seems to show the expected output.
Try this:
Inside Flutter, where you want to call the function, add:
http.get(Uri.parse('http://localhost:5001/my_project/us-central1/foo'))
You're going to have to set an env variable, that asks your application to check what environment it is in. If dev, then it should use url above, if prod it can use the prod url
this._cloudFunctions = FirebaseFunctions.instance;
_cloudFunctions.useFunctionsEmulator(origin: "http://<System's IP>:5001");
Systems ip we can get by typing ipconfig in command prompt.
Make sure you connect your ip and run emulators start.
For Flutter
As per the Firebase Flutter Docs-
There is a useFunctionsEmulator module as part of your Firebase Functions instance.
You can initialize it as follows:
FirebaseFunctions.instance.useFunctionsEmulator('localhost', 5001);
For Web
If you cd into the functions directory you can run npm start which will, by default, build and run the emulators locally in the shell. I've found this to be the only solution for testing callable functions locally.
The firebase team has provided a connectFunctionsEmulator submodule in the V9 modular SDK which is designed specifically to interact with your app locally.
You can checkout the official docs for this Here.
Running npm run serve will serve the emulator that you are expecting but I have been running into issues testing callable functions via url.
Related
I recently enabled App Check for my firebase app and enforced it on both my cloud functions and database. The cloud function workflow is behaving correctly. However, I can no longer access the database from the function. A minimal version of my callable function looks something like this:
exports.myFunc = functions.https.onCall(async (data, context) => {
const adminApp = admin.initializeApp();
const ref = adminApp.database().ref('some-node');
if (context.app === undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.',
);
}
try {
return (await ref.orderByKey().equalTo('foo').get()).exists()
} catch(exc) {
console.error(exc);
}
});
This used to work before App Check, but now it fails and I see this in the logs:
#firebase/database: FIREBASE WARNING: Invalid appcheck token (https://my-project-default-rtdb.firebaseio.com/)
Error: Error: Client is offline.
Seems like I need to do something extra to get the admin app to pass App Check verification down to the database, but I haven't been able to find any documentation on this yet. I also tried using the app instance from functions.app.admin instead of initializing a new one, but this didn't help.
I have the latest version of the packages:
"firebase-admin": "^9.10.0"
"firebase-functions": "^3.14.1"
firebaser here
The behavior you're seeing is not how it's supposed to work, and we've been able to reproduce it. Thanks for the clear report, and sorry you encountered this.
If you (re)install the Firebase Admin SDK today, you won't be experiencing this same problem as we've fixed the problem in the #firebase/database dependency (in this PR).
If you're (still) experiencing the problem, you can check if you have the correct #firebase/database dependency by running:
npm ls #firebase/database
results look something like this:
temp-admin#1.0.0 /Users/you/repos/temp-admin
└─┬ firebase-admin#9.11.0
└── #firebase/database#0.10.8
If your #firebase/database version is lower than 0.10.8, you'll have to reinstall the Admin SDK, for example by deleting your node_modules directory and your package-lock.json file and running npm install again. This may also update other dependencies.
We are trying to create a development environment before publishing our firebase functions.
We have successfully installed and started a local emulator, can access our firestore database, can call the HTTPS endpoints and everything. Starting firebase emulators:start shows:
firebase emulators:start --import=./testdata
i emulators: Starting emulators: functions, firestore, hosting, pubsub
⚠ functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, database
⚠ Your requested "node" version "12" doesn't match your global version "14"
i firestore: Importing data from /home/forest/projects/icell/i_cell_parking_manager/firebase/testdata/firestore_export/firestore_export.overall_export_metadata
i firestore: Firestore Emulator logging to firestore-debug.log
i pubsub: Pub/Sub Emulator logging to pubsub-debug.log
i hosting: Serving hosting files from: webserver
✔ hosting: Local server: http://localhost:5000
i ui: Emulator UI logging to ui-debug.log
i functions: Watching "..../firebase/functions" for Cloud Functions...
✔ functions[createParkingReservationsForNextWeek]: pubsub function initialized.
✔ functions[reserveSpaceForUser]: http function initialized (http://localhost:5001/i-cell-parking-manager-backend/us-central1/reserveSpaceForUser).
┌────────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! View status and logs at localhost:4000 │
└────────────────────────────────────────────────────────────────┘
┌───────────┬────────────────┬──────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├───────────┼────────────────┼──────────────────────────┤
│ Functions │ localhost:5001 │ localhost:4000/functions │
├───────────┼────────────────┼──────────────────────────┤
│ Firestore │ localhost:8080 │ localhost:4000/firestore │
├───────────┼────────────────┼──────────────────────────┤
│ Hosting │ localhost:5000 │ n/a │
├───────────┼────────────────┼──────────────────────────┤
│ Pub/Sub │ localhost:8085 │ n/a │
└───────────┴────────────────┴──────────────────────────┘
Other reserved ports: 4400, 4500
We have a function called createParkingReservationsForNextWeek which is a timed single pubsub, we want to trigger it without needing to wait for the scheduler.
*/
exports.createParkingReservationsForNextWeek = functions.pubsub
.schedule(WEEKLY_NOTIFICATION_SCHEDULE)
.timeZone(TIMEZONE_EUROPE_BUDAPEST)
....
According to https://firebase.google.com/docs/functions/local-emulator#web we can do that by navigation to this URL in a browser: http://localhost:5001/i-cell-parking-manager-backend/us-central1/createParkingReservationsForNextWeek
But upon that we get this error (which can be seen in the emulator logs as well):
functions: TypeError: Cannot read property 'data' of undefined
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:580:28
at Generator.next (<anonymous>)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
at __awaiter (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:4:12)
at processBackground (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:577:12)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:673:23
at Generator.next (<anonymous>)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
⚠ Your function was killed because it raised an unhandled error.
In the logs (http://localhost:4000/logs):
14:50:31
I
function[createParkingReservationsForNextWeek]
Beginning execution of "createParkingReservationsForNextWeek"
14:50:31
W
function[createParkingReservationsForNextWeek]
TypeError: Cannot read property 'data' of undefined
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:580:28
at Generator.next (<anonymous>)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
at __awaiter (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:4:12)
at processBackground (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:577:12)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:673:23
at Generator.next (<anonymous>)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
14:50:31
W
function[createParkingReservationsForNextWeek]
Your function was killed because it raised an unhandled error.
Cloud-firestore-emulator version is v1.11.9.
You can run a pub/sub function locally by calling it by name in the firebase shell:
Terminal 1: firebase emulators:start
Terminal 2: firebase functions:shell then createParkingReservationsForNextWeek()
If you need to include data on invocation (likely the cause of your error above), you can do so as well:
// invokes a function with the JSON message { hello: 'world' } and attributes { foo: 'bar' }
myPubsubFunction({data: new Buffer('{"hello":"world"}'), attributes: {foo: 'bar'}})
See the Firebase documentation for more details.
I'm building this cloud function in my local environment and I need to save something to Firestore:
Here's how I'm initializing the firebase-admin app:
myFunction.js
if (!adminHasInitialized) {
console.log("INITIALIZING ADMIN APP"); // THIS IS BEING LOGGED
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
adminHasInitialized = true;
}
And here's how I'm trying to update my Firestore:
await admin.firestore().collection("myCollection").doc("myDoc").update({
...
});
NOTE: I'm working on MY_PROJECT_1
And this is the error I'm getting:
details: 'No document to update: projects/MY_PROJECT_2/databases/(default)/documents/myCollection/myDoc',
PROBLEM
Somehow firebase-admin is looking inside another database for a different project MY_PROJECT_2 that I have.
When I run: firebase projects:list, this is what I get:
Project Display Name │ Project ID │ Resource Location ID
MY_PROJECT_1 │ MY_PROJECT_1 (current) │ us-central1
MY_PROJECT_2 │ MY_PROJECT_2 │ us-central1
So the current project is correct.
Also I have this file, which I set the default as MY_PROJECT_1
.firebaserc
{
"projects": {
"default": "MY_PROJECT_1"
}
}
I also tried to add the DB URL when I'm initializing the app, as:
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://MY_PROJECT_1.firebaseio.com"
});
But I keep getting the same error.
NOTE: I'm running this function in my local environment using babel-node throught the following command:
npx babel-node functions/src/myFunction.js
QUESTION
How is firebase-admin getting a different default project than the one I'm currently working on?
UPDATE 1
I think that firebase-admin is getting the default configuration from the gcloud SDK that is installed in my PC.
From:
[C:\Users\USER\AppData\Roaming\gcloud\configurations\config_default]
config_default:
[core]
account = my#email.com
project = MY_PROJECT_2 // MAYBE IT IS COMING FROM HERE
UPDATE 2
So far, the only thing I've managed to make it work is with:
admin.initializeApp({
projectId: "MY_PROJECT_1",
databaseURL: "https://MY_PROJECT_1.firebaseio.com"
});
This gives me the correct project when I run this function locally.
Since version 1.0.0 of the Firebase SDK for Cloud Functions you don't need anymore to initialize with admin.initializeApp(functions.config().firebase);, see the doc here, which explains that:
firebase-admin is now initialized without any parameters within the
Cloud Functions runtime.
So please try with:
if (!adminHasInitialized) {
console.log("INITIALIZING ADMIN APP");
admin.initializeApp();
adminHasInitialized = true;
}
I have a serverless REST API that uses NodeJS and Google Cloud Functions (Firebase). It works on production. But not locally for testing.
The app was created following the tutorial at: https://dev.to/levivm/creating-a-serverless-rest-api-using-google-cloud-functions-firebasefirestore-in-10-min-37km
When the firebase emulator is started locally the API endpoint seems not to work, and an error is returned:
URL http://my_local_server:8080/api/v1/my_api_route.
Output: Cannot GET /api/v1/my_api_route
The root url returns: http://my_local_server:8080/
{"status":"alive"}
Do you know what might cause the issue?
$ firebase emulators:start --only functions
i emulators: Starting emulators: functions
✔ functions: Using node#10 from host.
✔ functions: Emulator started at 0.0.0.0:8080
i functions: Watching "/home/ubuntu/environment/Crew-IQ/functions" for Cloud Functions...
⚠ functions: The Cloud Firestore emulator is not running, so calls to Firestore will affect production.
✔ functions[webApi]: http function initialized (0.0.0.0:8080/crew-iq/us-central1/w...).
✔ All emulators started, it is now safe to connect.
For that application, the endpoint would be
http://localhost:8080/crew-iq/us-central1/webApi/api/v1/my_api_route
└───┬───┘ └─┬┘ └──┬──┘ └────┬────┘ └──┬─┘└─────────┬────────┘
host │ │ │ │ │
port │ │ │ │
project ID │ │ │
function region │ │
function name │
your express app
I am trying to follow this tutorial from Firebase Web Codelab, but I am facing a problem at step 5: after running the command firebase serve, I do not get the expected response
Listening at http://localhost:5000, but instead I get:
i functions: Preparing to emulate functions.
i hosting: Serving hosting files from: ./
+ hosting: Local server: http://localhost:5000
which is bad because functions are not being served, although ⚠ functions: Failed to emulate api is not prompted, it remains "preparing to emulate functions" ad infinitum.
More information: CLI Version: 3.18.4
Platform: win32
Node Version: v6.12.3 and I already tried going to ~/.config/configstore/ and deleting the #Google-Cloud folder in order to restart the whole process.
I'm pretty sure you are in the right track, the difference between the expected message (Listening at http://localhost:5000) and the message you get (hosting: Local server: http://localhost:5000) is because you are using the new version of the CLI (v3.18.4) but the codelab chapter is not updated to reflect the new change in the logging message.
You can see the difference in the source-code firebase-tools v2.2.1 where it displays
Listening at http://<HOST>:<PORT>
and in firebase-tools v3.18.4 it displays
hosting: Local server: http://<HOST>:<PORT>
And for the functions emulation, as you are in step5, you don't have yet functions, see functions in the codelab source code.