Unable to receive req.body in controller when sending a message with file attachment

47 Views Asked by At

I'm building a chat application using Node.js and Express, and I'm facing an issue with receiving req.body in the controller when sending a message that includes a file attachment. I have the necessary code in place, but for some reason, the request body is not being parsed correctly.

async function sent(e) {
  try {
    e.preventDefault();
    const messageInput = document.getElementById("message-input");
    const message = messageInput.value;
    // ! trim() method to remove any leading or trailing whitespace from the message variable

    const groupId = localStorage.getItem("groupId");
    const fileInput = document.getElementById("file-input");
    const attachment = fileInput.files[0];
    console.log({ groupId, fileInput, attachment });

    if (message.trim() === "" && !attachment) {
      return;
    }
    // const context = {
    //   context: message,
    //   groupId: groupId,
    // };
    const formData = new FormData();
    formData.append("context", message);
    formData.append("groupId", groupId);
    formData.append("attachment", attachment);

    for (const [key, value] of formData.entries()) {
      console.log(key, value);
    }

    console.log(JSON.stringify(formData));

    const token = localStorage.getItem("token");
    const response = await axios.post(`${API_URL}/sendMessage`, formData, {
      headers: {
        Authorization: token,
        "Content-Type": "multipart/form-data",
      },
    });
    socket.emit("sendMessage", () => {
      console.log("FE: sent is getting emitted");
    });
    messageInput.value = "";
    fileInput.value = "";
  } catch (error) {
    console.log({ FunctionSentFE: error });
  }
}
<div class="input-container">
            <form action="#" method="post" onsubmit="sent(event)" enctype="multipart/form-data">
                <input type="text" id="message-input" name="input" placeholder="Type your message..." width="100%">
                <label for="file-input">
                    <i class="fa fa-paperclip attachment-icon"></i>
                </label>
                <input type="file" id="file-input" name="attachment" style="display: none;">
                <button id="send-button" type="submit">Send</button>
            </form>
        </div>

const { Op } = require("sequelize");

const multer = require("multer");

// ? M in the end of variables is for model
const MessageM = require("../models/messages");
const UserM = require("../models/users");

const { uploadToS3 } = require("../Services/s3services");

const sendMessage = async (req, res) => {
  try {
    console.log({ sendMessageBE: "sendMessageBE" });
    const { context, groupId } = req.body;
    console.log(req.body);
    // ? getting the email from the middleware
    const email = req.authUser.email;
    const user = await UserM.findOne({ where: { email } });
    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }
    let attachmentUrl;
    if (req.file) {
      // Uploading the file to S3
      const file = req.file;
      attachmentUrl = await uploadToS3(file.buffer, file.originalname);
    }
    const message = await MessageM.create({
      UserId: user.id,
      text: context || "",
      GroupGroupId: groupId,
      attachment: attachmentUrl, // Save the attachment URL in the database
    });
    res.status(201).json({ message });
  } catch (error) {
    console.error(error);
    res
      .status(500)
      .json({ error: "An error occurred while sending the message" });
  }
};

// ? Services: contain network calls, modifies controller folder
const AWS = require("aws-sdk");
const dotenv = require("dotenv");
const multer = require("multer");
dotenv.config();

const upload = multer().single("attachment");

async function uploadToS3(data, filename) {
  try {
    const BUCKET_NAME = process.env.BUCKET_NAME;
    const IAM_USER_KEY = process.env.IAM_USER_KEY;
    const IAM_USER_SECRET = process.env.IAM_USER_SECRET;
    // ? AWS related settings in the following link
    // https://youtu.be/ihZ6aHiOIWQ?list=PL4dunL3FOEk0XNSrauPcapBXdyojKlM9x&t=771

    let s3bucket = new AWS.S3({
      accessKeyId: IAM_USER_KEY,
      secretAccessKey: IAM_USER_SECRET,
    });

    var params = {
      Bucket: BUCKET_NAME,
      Key: filename,
      Body: data,
      ACL: "public-read",
    };
    return new Promise((resolve, reject) => {
      s3bucket.upload(params, (error, s3response) => {
        if (error) {
          console.log({ s3buckerError: error });
          reject(error);
        } else {
          // console.log({ s3bucketSuccess: s3response });
          resolve(s3response.Location);
        }
      });
    });
  } catch (error) {
    console.log({ uploadToS3ControllerError: error });
  }
}

module.exports = {
  uploadToS3,
  upload,
};

Here's what I have already checked and tried:

I have confirmed that the necessary middleware (e.g., express.json() or multer) is properly configured and registered in my backend.

I have included the Content-Type header as "multipart/form-data" in my Axios request from the frontend.

Despite these efforts, when I send the message with a file attachment, the req.body in the backend controller is empty or undefined. As a result, I cannot access the message context or other data.

0

There are 0 best solutions below