0

I have an Express.js app which I use a REST API to interact with Firebase Storage and Realtime Database. I set up a Firebase project where I use Firebase Functions. I have one main function which is basically the entry point for all requests to my Express app:

// export express app to functions
exports.api = functions.https.onRequest(app);

where app is my Express app initialized.

One of the routes is used to upload an image to Firebase Storage. Here is the code for it:

/* POST upload user profile picture. */
router.post('/:username/upload_profile_picture', async function(req, res, next) {
  try {

    const bb = Busboy({ headers: req.headers });
    let fileData = null;
    let fileBlob = null;
    bb.on('file', function (fieldname, file, filename, encoding, mimetype) {
      const filepath = path.join(os.tmpdir(), filename.filename);
      fileData = { filePath: filepath, type: mimetype };
      file.pipe(fs.createWriteStream(filepath));
    });
    bb.on('finish', async () => {
      const profilePicture = await UserRepository.uploadProfilePicture(fileData.filePath, req.params.username);
      if (profilePicture == null) {
        res.status(400).json({ message: "Image upload failed" });
      } else {
        res.status(200).json({ message: "Image uploaded successfully", profilePicture: profilePicture });
      }
      fs.unlinkSync(fileData.filePath);
    });
    req.pipe(bb);
  } catch (error) {
    next(error);
  }
});

And here is the corresponding function called in my UserRepository:

exports.uploadProfilePicture= async (filePath, user) => {
    const file = fs.readFileSync(filePath);
    const imageRef = storage_ref(storage, 'profilePictures/' + user);
    try {
        await uploadBytes(imageRef, file.buffer);
        console.log('Uploaded file to firebase');
        const url = await getDownloadURL(imageRef);
        return url;
    } catch (error) {
        console.log(error);
    }
}

When I run my Express app locally using npm run dev, images are uploading successfully. However whenever I use the Firebase Emulator, I get the following error:

>  Error: Unexpected end of form
>      at Multipart._final (/Users/cesar/ProgrammingProjects/Democrastyle/backend/node_modules/busboy/lib/types/multipart.js:588:17)
>      at callFinal (node:internal/streams/writable:698:12)
>      at prefinish (node:internal/streams/writable:710:7)
>      at finishMaybe (node:internal/streams/writable:720:5)
>      at Writable.end (node:internal/streams/writable:634:5)
>      at onend (node:internal/streams/readable:705:10)
>      at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
>  Emitted 'error' event on Multipart instance at:
>      at Multipart.onerror (node:internal/streams/readable:785:14)
>      at Multipart.emit (node:events:513:28)
>      at emitErrorNT (node:internal/streams/destroy:151:8)
>      at emitErrorCloseNT (node:internal/streams/destroy:116:3)
>      at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

I read somewhere that the Multer library was causing this issue because Firebase does not support it, and that's why I migrated to using Busboy but I am still getting the same error. Using the Firebase Emulator, all other routes work fine. Only the routes that contain form-data are failing (although everything works locally).

N.B: I tried deploying the Firebase Functions but I get the same behaviour as the Emulator.

1 Answers1

1

I can't find any reference to storage_ref. The docs and code seem to use ref: https://firebase.google.com/docs/storage/web/upload-files#upload_from_a_blob_or_file.

Also, you shouldn't need the .buffer from file as the uploadBytes method says:

// 'file' comes from the Blob or File API.

Try: uploadBytes(storageRef, readFileSync(file.path));

Chris
  • 846
  • 6
  • 16