Request with header {"Content-Type": "multipart/form-data;"} sends empty req.body

Viewed 54

I'm trying to save the formData below to MongoDB. In the payment below, "attachments" is a FileList.

What's happening is the response in the create controller returns an empty body when the header content type is multipart/form-data. Otherwise, the create controller adds all the fields but not attachments. That returns an empty array.

What could I do on my controller so that I can create the payment with the attachment?

const handlePaymentSubmit = async (e) => {
    e.preventDefault();
    let payment = new FormData();
    payment.append("payee", user.id);
    payment.append("amount", paymentAmount);
    payment.append("code", paymentCode);
    payment.append("method", paymentMethod);
    payment.append("applicationId", applicationId);
    payment.append("attachments", attachments);
    await createPayment(payment);
    {
      isSuccess && dispatch(reset());
    }
  };

In createPayment RTK Endpoint I set the headers content-type to multipart form data

createPayment: builder.mutation({
      query: (payment) => ({
        url: "/api/payments/",
        method: "POST",
        body: payment,
        headers: {
          "Content-Type": "multipart/form-data;",
        },
      }),

On the backend, I set how to store the files in middleware with Multer.

import multer from "multer";

var storeImage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/payments");
  },
  filename: function (req, file, cb) {
    let ext = file.originalname.substring(file.originalname.lastIndexOf("."));
    let name = file.originalname.substring(0, file.originalname.indexOf("."));
    cb(null, name + "-" + Date.now() + ext);
  },
});

export const storage = multer({
  storage: storeImage,
  fileFilter: function (req, file, cb) {
    if (
      (file.mimetype =
        "image/png" || "image/jpg" || "image/jpeg" || "application/pdf")
    ) {
      cb(null, true);
    } else {
      console.log("Only pdf, jpg and Png Supported");
      cb(null, false);
    }
  },
  limits: {
    fileSize: 1024 * 1024 * 2,
  },
});

And create the payment in my create controller.

import asyncHandler from "express-async-handler";
import formidable from "formidable";
import Payment from "../../models/payment.js";

export const createPayment = asyncHandler(async (req, res) => {
  const { payee, amount, code, method, applicationId } = await req.body;

  if (!payee || !amount || !code || !method || !applicationId) {
    res.status(400);
    throw new Error("Please add all required fields");
  }

  if (req.files) {
    let path = "";
    req.files.forEach(function (files, index, arr) {
      path = path + files.path + ",";
    });
    path = path.substring(0, path.lastIndexOf(","));
  }

  const attachments = req.files.map((attachment) => ({
    path: attachment.path,
    name: attachment.filename,
    size: `${(attachment.size / 1000).toFixed(2).toString()} KBs`,
  }));

  const payment = await Payment.create({
    payee,
    amount,
    code,
    method,
    applicationId,
    attachments,
  });

  res.status(200).json(payment);
});

0 Answers
Related