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
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 });
});
});
This is how you make the API Call
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);
});