I've a use case, where in I want to maintain some rarely changing constants in firebase and load them into my cloud functions project (project-1) when there is a constants.changed config value is set to true. During the next request execution, I'll update my JS file with modified constants and reload the node cache for that file using
delete require.cache[require.resolve('./constants.js')].
Also, here I want to re-set the flag constants.changed to false so that next request won't really do the same thing!. In this way I can avoid hitting firebase continuously in each request for that rarely changing constants document.
I could set this config manually, but I've another system (cloud functions project [project-2]) which actually makes these changes to the constants. Hence I want the cloud function in project-2 to to set the firebase cloud functions config value constants.changed to true.
Am I running after a mirage? is this even possible to achieve. I've checked int the documentation, but seems the Config interface is not exposing such a functionality!
It is not possible to achieve what I said in the question!
Two basic premise is not considered in the above requirement narration.
Cloud functions config when changed, the cloud functions using that config need to be re-deployed to make the changes take effect.
Seems the cloud functions running on the server are in read only file system.
Both the above two limitations makes it impossible to achieve what I've asked for. But it would be a nice to have feature (hot deployments!)
Related
I have a collection that needs to be updated. There's a need to add new field and fill it out based on the existing field.
Let's say I have a collection called documents:
documents/{documentId}: {
existingField: ['foo', 'bar'],
myNewField ['foo', 'bar']
}
documents/{anotherDocumentId}: {
existingField: ['baz'],
myNewField ['baz']
}
// ... and so on
I already tried to fire up local cloud function from emulator that loops for each document and writes to production data based on the logic I need. The problem is that function can only live up to max of 30 seconds. What I need would be some kind of console tool that I can run as admin (using service-account) to quickly manage my needs.
How do you handle such cases?
Firebase does not provide a console or tool to do migrations.
You can write a program to run on your development machine that uses the one of the backend SDKs (like the Firebase Admin SDK) to query, iterate, and update the documents and let it run as long as you want.
There is nothing specific built into the API for this type of data migration. You'll have to update each document in turn, which typically involves also reading all documents (or at least their IDs).
While it is possible to do this on Cloud Functions, I find it easier to do it with a local Node.js script, as that doesn't have the runtime limits Cloud Functions imposes.
This question was previously closed, telling me to "update the question so it focuses on one problem only;" I don't know what the problem is, and if I did, I wouldn't be posting this question. Regardless, I'll make some clarifications here:
I was previously using just the normal Firebase module (the one imported using "npm i firebase"); everything worked perfectly before. The issue has to do with the authentication (as far as I am aware) with the Firebase Admin SDK. I don't understand how I'm supposed to send this to the Heroku build without revealing the service account key JSON file on my GitHub.
As for the GOOGLE_APPLICATION_CREDENTIALS path, is there a way where I don't have to set it every session? The Heroku app restarts once a day, and I would need to somehow automate this entry process (or skip it entirely). That's the way I currently understand it. Here's a quote from a previous answer:
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine?
Environment variables only work on the individual machine and process where they have been set. If you want it set on another machine and process, you will have to arrange for that separately. According to the documentation:
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.
My main question here is as follows: "I implemented the Firebase Admin SDK incorrectly. How do I do it the right way?"
Even just posting a link to guides that would help would be appreciated (although I understand this is typically discouraged as links sometimes break).
Original:
Note: this is my first time using the Firebase Admin SDK, so I'm really not sure what I'm doing (although I have used Firebase quite a bit).
Recently, I decided I would go back to one of my older Discord bots and actually authenticate its requests to Firebase properly (I hadn't done this previously as I've never authenticated from a server before and didn't think it was possible). I discovered the Firebase Admin SDK, which sounded perfect for my needs (the bot is being hosted on Heroku, for the record).
I found this guide: https://firebase.google.com/docs/admin/setup, but there's a few things I can't wrap my head around (note that these are purely rhetorical, you don't need to answer them in your answer; I'm just providing them so you can understand my thought process):
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine? I could also try running the export command on the server (using "heroku run" in the CLI), but then the path would be pointing to a file that doesn't exist on the server (since the service account key JSON file is on my local machine). Do I need to set an environment variable in Heroku or something?
How does "admin.credential.applicationDefault()" know how to get the credentials?
I can't find any other guides that make sense.
The way I currently have it setup must be wrong, since reads and writes fail silently.
Firebase setup code:
// Setup Firebase:
const admin = require('firebase-admin');
// Initialize Firebase:
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://<APP>.firebaseio.com" // I removed the actual <APP> name to ask this question
});
let database = admin.database();
Things like database.ref("test").set("Hello World!"); don't change the data in the database, and no errors are thrown (I've also tried attaching a .then and a .catch to the end of this; still nothing). This was working before I switched over to the Firebase Admin SDK (I was just using the "firebase" module previously, rather than the "firebase-admin" module that I'm now using). The same goes for reading data.
Any help would be appreciated.
Here was my problem:
I was sending res.status(200) outside of the async firebase call, killing the request before firebase had a chance to finish. Somehow localhost allows this to work properly but when its hosted things go sideways.
so I had this
fireabse.database().ref('parent/foo').set('bar');
res.status(200)
I needed this:
firebase.database().ref('parent/foo').set('bar').then(() => {
res.status(200);
});
I have a project were I set up keys as such.
Live keys
functions:config:set stripe.secret="sk_live_..." stripe.publishable="pk_live_..."
Test keys
functions:config:set stripe.secret="sk_test_..." stripe.publishable="pk_test_..."
The application is in its beta stage but live. So there's a lot more changes still done in code.
So I want to avoid setting the keys each time I want to test out some new feature on localhost.
Is there a way to configure firebase functions, to correspond to different Environments?
When on localhost, it should validate with test keys and with on remote live keys?
There isn't a special per-environment configuration. What you can do instead is use the unique id of the project to determine which settings it should apply. Functions can read the deployed project id out of the process environment with GCP_PROJECT
const project_id = process.env.GCP_PROJECT
The values you should use during development is a matter of opinion - do whatever suits you the best.
I believe you can make a .runtimeconfig.json file in your functions directory, which the emulators will read.
For example, first set your local values with `firebase functions config:set stripe.secret="sk_test_...",
Then, run firebase functions config:get > .runtimeconfig.json
When that file is present, from my experience, your firebase emulators will read from that, and you won't keep overwriting production config variables.
Docs: https://firebase.google.com/docs/functions/local-emulator#set_up_functions_configuration_optional
While I find the Cloud Functions in Firebase fairly convenient, I have troubles figuring out how to configure them in any way. the firebase init generated the firebase.json that contains functions.predeploy property, but are there any other options available? I cannot find any schema for this file.
By default my cloud function is deployed as Node.js 6 application. How do I define that I want to use Node.js 8 which is already supported by the platform? How can I change the amount of used memory? How do I define the environment variables? All of these can be specified through cli commands or from UI, but will be overriden during the next deployment. Isn't there something I could add to my firebase.json that would allow me to specify these values as a permanent thing? Or is it that I actually have to work with the full-blown Google Cloud and the Deployment Manager in order to get it to work?
All of your questions are answered in the documentation.
Set the node version.
Set the version by adding an engines field to the package.json file
that was created in your functions/ directory during initialization.
For example, if you prefer to use only version 8, edit package.json to
add this line:
"engines": {"node": "8"}
Specify other runtime config.
To set memory allocation and timeout in functions source code, use the
runWith parameter introduced in Firebase SDK for Cloud Functions
2.0.0. This runtime option accepts a JSON object conforming to the RuntimeOptions interface, which defines values for timeoutSeconds and
memory. For example, this storage function uses 1GB of memory and
times out after 300 seconds:
const runtimeOpts = { timeoutSeconds: 300, memory: '1GB' }
exports.myStorageFunction = functions
.runWith(runtimeOpts)
.storage
.object()
.onFinalize((object) = > {
// do some complicated things that take a lot of memory and time });
Set environment config.
I am building a very simple cron job backup system for a friend's firebase app;
I have PHP code, using firebase-php that can communicate with the firebase and the API docs state that adding the'?format=export" parameter will retrieve a .json file. Cool, so far.
My question is this: What path (after the firebase URL) is required?
The API doc appears to state that it should be /.json but it returns a 404 /json/ works on the simulator, but also returns a 404 in testing
(note: looking for a single text file, similar to the "Export json" data dashboard, if possible)
Thanks in advance.
The path defined the portion of the Firebase data tree that is being loaded. That means that you can load /any/possible/string and it will return a value, though that value is likely to be null unless you've written data to that path. Also note that without a defined extension (i.e. .json) you'll be attempting to load Firebase's in-browser graphical debugger.
In short, if you're using the REST API, you'll always want to end your paths in .json, but nothing else is required, i.e. https://<your-firebase>.firebaseio.com/.json is perfectly valid, and would download your entire Firebase. The format=export parameter ensures that any Firebase priority values are preserved in your JSON output, under the key .priority at any node, where they would normally be excluded.