DEV Community

Aaron K Saunders
Aaron K Saunders

Posted on • Edited on

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

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 });
    });
});
Enter fullscreen mode Exit fullscreen mode

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);
  });
Enter fullscreen mode Exit fullscreen mode

ko-fi

Top comments (1)

Collapse
 
ivanandresdiaz profile image
Ivan Andres Diaz

I have a problem. When it is upload in firestorage it appers a type like this "application/octet-stream". instead of image/jpeg. is there any extra step ?