Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make the Firebase functions emulator trigger based on a database emulator update

In short, I want to test a Firebase function locally, specifically one that is triggered from a realtime database trigger. According to the docs for local testing, it seems that there are two ways of accomplishing local testing of Firebase functions:

  • Using the firebase functions emulator (firebase emulators:start --only functions)
  • Using the firebase functions shell (firebase functions:shell)

First, the differences between the two, at least in the linked guide, are very unclear. For the Firebase folks reading this, doc updates here would be great (considering local testing of this stuff is such an important feature).

My focus in this question (with respect to what I've tried) is based on the emulator, namely because it's mentioned that there are "interactions with other services". Interestingly, the list there only includes two items:

  • Cloud Firestore
  • Firebase Hosting

There is a notable omission of Realtime Database, and maybe that's where the gap is, but here we go.

My function looks something like this:

console.log("Hello World")

exports.myDatabaseTrigger = functions.database.ref('/a/path/{id}').onCreate((data, context) => {
  console.log(`myDatabaseTrigger triggered - here's my path ${data.ref.path}`);

  //manipulate some other stuff in the DB
})

In my project, I am using both Functions and Realtime Database, so I run the command firebase emulators:start and it starts up both emulators.

In Postman, I use the local Realtime Database REST API to post some data with the following params:

POST
http://localhost:9000/a/path.json
{
  "some": "data"
}

And I get back a response containing the name of the newly created item under /a/path. However, my Firebase function never fires, and I never see the inner log (although the Hello World log does print when the emulator starts).

So, is the interaction between these two emulators possible? Or, am I forced to use the functions shell? My issue with the shell is that, based on the realtime database examples, it's not clear what the DataSnapshot variables (i.e. data.ref.path) will be if I simply call my function with some random value (e.g. myDatabaseTrigger({"some": "data"})).

like image 581
MandM Avatar asked Mar 02 '23 20:03

MandM


1 Answers

It looks like you may have just forgotten the project/namespace ID.

Try adding the ?ns= parameter to your POST:

POST
http://localhost:9000/a/path.json?ns="YOUR_PROJECT_ID"
{
  "some": "data"
}

Emulated functions only trigger from writes to a single database instance, just like in production.

As for your points of confusion:

  • functions:shell is just a REPL for functions. It does not emulate any other services (Database, Firestore, etc). Instead you directly pass in the data that would come from those services.
  • If you want to test Functions <--> Database interactions use emulators:start --only database,functions
  • In general the rule with emulators:start is that we comprehensively emulate whatever is running. So for example if you're running the Functions and Database emulator, all writes from functions (through admin.database().... will be redirected to the Database emulator. But writes to Firestore (admin.firestore()...) will try and hit production because that emulator is not running.
like image 187
Sam Stern Avatar answered Mar 05 '23 11:03

Sam Stern