I needed to upload a binary file ( a document, pdf or image file) from a Node JavaScript application to Cloud Storage for FireBase (similar to AWS S3). This is for a application similar to a recent public github repo.
Documentation was a mess and I had 2 (code) problems.
- Which api to use. This was complicated by the fact the api’s for uploading came in multiple flavors (client or server; ESM or older CJS; and Google or Firebase – the google ones generally being a wrapper of the firebase ones). Also lots of code examples none of which seemed to cover my use case or include the second part.
- Making sure I had the proper credentials to allow access to Firebase services, particularly for a node server, where it is not always clear which type of credentials you need, and if you get that wrong the error message is not clear how to correct the issue.
This post is to provide a example of what worked for me, based on the current LTS version of node v20.x, and the firebase-admin version 12.0.0, and a code module at this gist
To get the right access credentials I created a `Firebase service account` for the project, and used it to initialize the application.
1 2 | app = await initializeApp( credential: applicationDefault(), ..) |
and passing in the values via applicationDefault() from the serviceAccount object saved to the serviceAccount json file and exported to local environment by exporting then on the command line :
1 | export GOOGLE_APPLICATION_CREDENTIALS="application_default_credentials.json" |
Note: best practices for security is to NOT to commit the application_default_credentials.json file, at minimum to include the file in the .gitignore file. Not doing so is a frequent source of data breaches and unexpected bills. Most hosting systems will have some way to store environment variables. (also be very careful logging credentials and api tokens)
The next step was to arrange a file to store in :
1 2 | const storage = await getStorage(); const file = await storage.bucket().file(`${fileNameForUpload}`); |
and then save the binary into that file
1 2 | const buffer = await Buffer.from(fileBinary); await file.save(buffer, {metadata: metadata,}) |
and then handle the success or error of that.
Depending on your needs, I might move the `initializeApp()` part of the code above the `uploadBinary()` function to be run once on load (with its own try catch block), rather than per upload if this is a longer run application.
There are almost certainly other ways to get this to work, but every other code spike didn’t quite work. Hope this helps.