0

I am developing a react application which uses react-dropzone hook to implement drag and drop file upload feature. I am then sending the file via a POST request to a firebase cloud function.

I am using BusBoy to write the received file to a tmpdir and upload the received file to firebase storage.

BusBoy file event is not firing in my cloud function.

Frontend


const onDrop = useCallback((acceptedFiles) => {
    // Check whether excel file is uploaded
    if (
      acceptedFiles[0].type == `application/vnd.ms-excel`.trim() ||
      acceptedFiles[0].type ==
        `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    `.trim()
    ) {
      auth.currentUser.getIdToken().then((token) => {
        let bodyFormData = new FormData();
        bodyFormData.append('file', acceptedFiles[0]);
        axiosInstance
          .post('/upload', bodyFormData, {
            crossdomain: true,
            headers: {
              Authorization: `Bearer ${token.toString()}`,
              'Access-Control-Allow-Origin': '*',
              'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
            },
          })
          .then((res) => {
            console.log(res);
          })
          .catch((err) => {
            console.log(err);
          });
      });
    } else {
      setFileTypeError(true);
    }
  }, []);

Request Header Content-Type is multipart/form-data; boundary=----WebKitFormBoundaryRWo4LrjStmEjoZll

and Form Data is file:{binary}

enter image description here

Backend

app.post('/upload', verifyAuth, (req, res) => {
  const BusBoy = require('busboy');
  const path = require('path');
  const os = require('os');
  const fs = require('fs');

  const busboy = new BusBoy({ headers: req.headers });

  let tempFileName;
  let fileToBeUploaded = {};

  busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
    console.log('file received');
    const fileExtension = filename.split('.')[filename.split('.').length - 1];
    tempFileName = `bulk-upload-${shortid.generate()}.${fileExtension}`;
    const filePath = path.join(os.tmpdir(), tempFileName);
    fileToBeUploaded = { filePath, mimetype };
    file.pipe(fs.createWriteStream(filePath));
  });

  busboy.on('finish', () => {
    bucket
      .upload(fileToBeUploaded.filePath, {
        resumable: false,
        metadata: {
          metadata: {
            contentType: fileToBeUploaded.mimetype,
          },
        },
      })
      .then(() => {
        return res.status(200).json({ success: true });
      })
      .catch((err) => {
        return res.status(400).json({ error: err });
      });
  });
});

Busboy On file event is not getting fired. I also checked req.file, this returns undefined. Could anyone help where I have gone wrong?

Sriram J
  • 174
  • 1
  • 1
  • 9

1 Answers1

0

I had the same problem, the file event doesn't fire when I sent a file with a multipart/form to a express firebase cloud function. I read other post that suggest to remove other middleware that can read the file stream from the request, but it was not work for me and nowadays I don't fix this yet.

But, a possible alternative is use the Firebase API for first upload the picture from the client app directly to the bucket and then do some action (in my case save a record on the database) :

 
      var photoRef = storage.ref().child(photoName);

      var uploadTask = photoRef.put(this.post.photo);

      uploadTask.on(
        "state_changed",
        (snapshot) => {
          // Observe state change events such as progress, pause, and resume
          // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
          
        },
        (error) => {
          // Handle unsuccessful uploads
        },
        () => {
          // Handle successful uploads on complete
          
          uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
            console.log("File available at", downloadURL);
            db.collection("images")
              .doc(fields.id)
              .set({
                id: fields.id,
                caption: fields.caption,
                location: fields.location,
                date: parseInt(fields.date),
                imageUrl: downloadURL,
              })
              .then(() => {
                console.log("Post added: " + fields.id);
              });
          });
        }
      );

In the case that you need do something with the file on the server, you can upload it first to the bucket and next retrieve it on a cloud function.

Xavi Torrens
  • 337
  • 1
  • 12