node.jsfirebasepostmangoogle-cloud-storagebusboy

Busboy: upload file and accessing req.body


I'm a newbie to backend development in general. but I wanted to upload files to firebase and I came across this tedious tool called busboy which works fine when uploading files. the problem though I wanted to upload a file and extract informations within the req.body but I'm getting req.body undefined. here is my code

    const Busboy = require("busboy");
    const path = require("path");
    const os = require("os");
    const fs = require("fs");
    const { admin, db, config } = require("../../util.js");

    exports.postimage = async (req, res) => {
      try {
        const description = req.body.description;
        const busboy = new Busboy({ headers: req.headers });
        let name;
        let image = {};
        let url;
        busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
          if (mimetype !== "image/png") {
            return res.status(400).json({
              error: "This extension is not supported. Please upload a png image",
            });
          }
          const extension = filename.split(".").pop();
          name = `${Math.round(Math.random() * 10000000000000)}.${extension}`;
          const filepath = path.join(os.tmpdir(), name);
          image = { filepath, mimetype };
          file.pipe(fs.createWriteStream(filepath));
        });
        busboy.on("finish", async () => {
          await admin
            .storage()
            .bucket()
            .upload(image.filepath, {
              resumable: false,
              metadata: {
                metadata: {
                  contentType: image.mimetype,
                },
              },
            });
          url = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${name}?alt=media`;
          await db.collection("images").add({
            url,
            description,
            createdAt: new Date().toISOString(),
          });

          return res.json({ meassage: "uploaded" });
        });
        busboy.end(req.rawBody);
      } catch (e) {
        return res
          .status(500)
          .json({ error: `Error, could not upload file: ${e}` });
      }
    };

Edit: the problem might be from the postman side which doesn't allow to send multipart and JSON data at once


Solution

  • I ended up using this workaround to achieve what I've been looking for

    1- in your postman use body > formdata. and then put as many fields as you want by filling the key/value areas

    2- in your in the code in the top of try{} I add this const body = {} and after you use this code snippet

     busboy.on(
      "field",
      function (
        fieldname,
        val,
        fieldnameTruncated,
        valTruncated,
        encoding,
        mimetype
      ) {
        body[fieldname] = val;
      }
    );
    

    finally, you can add in collection like this

      await db.collection("images").add({
       url,
       description: body.description,
      });