Using Firebase Emulator for Testing File Upload to Firebase Storage Using Firebase Functions

Using Firebase Emulator for Testing File Upload to Firebase Storage Using Firebase Functions

ยท

2 min read

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);
  });
ย