Using Firebase Emulator for Testing File Upload to Firebase Storage Using Firebase Functions
This is the source code to support the video tutorial on setting up Firebase Emulator to test using firebase cloud functions for uploading a file to firebase storage and more importantly getting a download url for retrieving the file later.
In the video I walkthrough setting up the environment for running locally along with how to use formidable-serverless npm library for extracting the file objects from the request body to upload to storage.
Bonus code here also shows how to create a download url to access the image from firebase storage. The getDownloadUrl call you would make from the client api does not work and the getSignedUrl used on the server provides a url that has a max duration of only seven days
Video
Potential Issues
- make sure you have the appropriate bucket name when uploading the image
- make sure you have downloaded and used the correct service-account.json file for your project
Source Code
const functions = require("firebase-functions");
const formidable = require("formidable-serverless");
const firebase = require("firebase-admin");
const UUID = require("uuid-v4");
const { Storage } = require("@google-cloud/storage");
firebase.initializeApp();
exports.uploadFile = functions.https.onRequest((req, res) => {
var form = new formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, async (err, fields, files) => {
var file = files.file;
if (!file) {
reject(new Error("no file to upload, please choose a file."));
return;
}
var filePath = file.path;
console.log("File path: " + filePath);
const storage = new Storage({
keyFilename: "service-account.json",
});
let uuid = UUID();
const response = await storage.bucket("default_bucket").upload(filePath, {
contentType: file.type,
metadata: {
metadata: {
firebaseStorageDownloadTokens: uuid,
},
},
});
const fullMediaLink = response[0].metadata.mediaLink + "";
const mediaLinkPath = fullMediaLink.substring(
0,
fullMediaLink.lastIndexOf("/") + 1
);
const downloadUrl =
mediaLinkPath +
encodeURIComponent(response[0].name) +
"?alt=media&token=" +
uuid;
console.log("downloadUrl", downloadUrl);
resolve({ fileInfo: response[0].metadata, downloadUrl }); // Whole thing completed successfully.
});
})
.then((response) => {
res.status(200).json({ response });
return null;
})
.catch((err) => {
console.error("Error while parsing form: " + err);
res.status(500).json({ error: err });
});
});
here is how you call the cloud function
let headersList = {
Accept: "*/*",
"User-Agent": "Thunder Client (https://www.thunderclient.io)",
};
// create the form
let formdata = new FormData();
// this is a hardcoded file path for the purpose of this
// example
formdata.append(
"file",
"/Users/aaronksaunders/Downloads/Learn to Build Mobile Apps With Ionic Framework, VUEJS, and Capacitor (8).png"
);
// this is the url to the emulator firebase service
fetch("http://localhost:5001/demo-test/us-central1/uploadFile", {
method: "POST",
body: formdata,
headers: headersList,
})
.then(function (response) {
return response.text();
})
.then(function (data) {
console.log(data);
});