hoangvvo/next-connect

Issues making multer file optional

Closed this issue · 1 comments

Hello, I'm having difficulty trying to make one of the files uploaded via multer optional. I'm using next-connect as a middleware.

`import { getSession } from "next-auth/react";
import Video from "../../../../../db/models/video";
import User from "../../../../../db/models/user";
import multer from "multer";
import path from "path";
import { createRouter, expressWrapper } from "next-connect";
import cloudinary from "cloudinary";
import DatauriParser from "datauri/parser";

const parser = new DatauriParser();

cloudinary.v2.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});

export const config = {
api: {
bodyParser: false,
},
};

const storage = multer.memoryStorage();
const upload = multer({
storage: storage,
limits: {
fieldSize: 28000000,
},
});

const router = createRouter();
router
.use(
expressWrapper(
upload.fields([{ name: "image", maxCount: 1 }, { name: "video" }]) // want to make video optional
)
)
.post(async (req, res) => {
const session = await getSession({ req });
if (!session) return res.status(400).json({ message: "Not Authorised!" });

const {
  title,
  description,
} = req.body;
const image = req.files["image"][0];
const video = req.files["video"][0];


if (!title || !description) {
  return res.status(400).json({ message: "Fill in all fields" });
}

if (image === undefined) {
  return res.status(400).json({ message: "Fill in image field" });
}
if (image.fieldname !== "image") {
  return res.status(400).json({ message: "File must be of image" });
}
if (image.size > 5000000) {
  return res
    .status(400)
    .json({ message: "Image size must be less than 5MB" });
}

try {
  if (req.method === "POST") {
    const userid = session?.user?.id;

    const user = await User.findOne({
      where: { id: userid },
    });

    if (!user)
      return res.status(400).json({ message: "User does not exist!." });

    const formatImageTo64 = (file) =>
      parser.format(
        path.extname(file.originalname).toString(),
        file.buffer
      );

    const cloudinaryImageUpload = (file) =>
      cloudinary.uploader.upload(file);

    const image64 = formatImageTo64(image);
    const uploadImageResult = await cloudinaryImageUpload(image64.content);

    if (typeof video === "object") {

      if (video.fieldname !== "video") {
        return res.status(400).json({ message: "File must be of video" });
      }

      if (video.size > 28000000) {
        return res
          .status(400)
          .json({ message: "Video size must be less than 28MB" });
      }
      const formatVideoTo64 = (file) =>
        parser.format(
          path.extname(file.originalname).toString(),
          file.buffer
        );

      const cloudinaryVideoUpload = (file) =>
        cloudinary.v2.uploader.upload(file, { resource_type: "video" });

      const video64 = formatVideoTo64(video);
      const uploadVideoResult = video
        ? await cloudinaryVideoUpload(video64.content)
        : null;

      const userId = user?.id;

      const newVideo = await Video.create(
        {
          title,
          image: uploadImageResult.url,
          video: uploadVideoResult.url,
          video_id: uploadVideoResult.public_id,
          video_signature: uploadVideoResult.signature,
          description,
          image_id: uploadImageResult.public_id,
          image_signature: uploadImageResult.signature, 
          user_id: userId
   } );

      if (!newVideo)
        return res.status(400).json({ message: "Can't add new video" });

      res.status(200).json({
        message: "Video was successfully created",
        newVideo,
      });
    } else {
      const userId = user?.id;

      const newVideo = await Video.create(
        {
          title,
          image: uploadImageResult.url,
          description,
          image_id: uploadImageResult.public_id,
          image_signature: uploadImageResult.signature,
          user_id: userId
            },
      );

      if (!newVideo)
        return res.status(400).json({ message: "Can't add new video" });

      return res.status(200).json({
        message: "Video was successfully created",
        newVideo,
      });
    }
  } else {
    res.status(500).json({ message: "HTTP method not valid" });
  }
} catch (err) {
  return res.status(500).json({
    message: "Internal error",
    err,
  });
} });

export default router.handler({
onError: (err, req, res) => {
console.error(err.stack);
res.status(500).json({ message: Fill in video/image field });
},
onNoMatch: (req, res) => {
res.status(404).json({ message: "Page is not found" });
},
});

`

I have no issues when I upload both image and video together but anytime I upload only the image, I get an error which says "Fill in video/image field"

This is how I solved it.

const video = (req.files["video"] || [])[0];
instead of

const video = req.files["video"][0];

So this is my full code:

`
import { getSession } from "next-auth/react";
import Video from "../../../../../db/models/video";
import User from "../../../../../db/models/user";
import multer from "multer";
import path from "path";
import { createRouter, expressWrapper } from "next-connect";
import cloudinary from "cloudinary";
import DatauriParser from "datauri/parser";

const parser = new DatauriParser();

cloudinary.v2.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});

export const config = {
api: {
bodyParser: false,
},
};

const storage = multer.memoryStorage();
const upload = multer({
storage: storage,
limits: {
fieldSize: 28000000,
},
});

const router = createRouter();
router
.use(
expressWrapper(
upload.fields([{ name: "image", maxCount: 1 }, { name: "video", maxCount: 1 }]) // want to make video optional
)
)
.post(async (req, res) => {
const session = await getSession({ req });
if (!session) return res.status(400).json({ message: "Not Authorised!" });

const {
title,
description,
} = req.body;
const image = req.files["image"][0];
const video = (req.files["video"] || [])[0];

if (!title || !description) {
return res.status(400).json({ message: "Fill in all fields" });
}

if (image === undefined) {
return res.status(400).json({ message: "Fill in image field" });
}
if (image.fieldname !== "image") {
return res.status(400).json({ message: "File must be of image" });
}
if (image.size > 5000000) {
return res
.status(400)
.json({ message: "Image size must be less than 5MB" });
}

try {
if (req.method === "POST") {
const userid = session?.user?.id;

const user = await User.findOne({
  where: { id: userid },
});

if (!user)
  return res.status(400).json({ message: "User does not exist!." });

const formatImageTo64 = (file) =>
  parser.format(
    path.extname(file.originalname).toString(),
    file.buffer
  );

const cloudinaryImageUpload = (file) =>
  cloudinary.uploader.upload(file);

const image64 = formatImageTo64(image);
const uploadImageResult = await cloudinaryImageUpload(image64.content);

if (typeof video !== "undefined") {

  if (video.fieldname !== "video") {
    return res.status(400).json({ message: "File must be of video" });
  }

  if (video.size > 28000000) {
    return res
      .status(400)
      .json({ message: "Video size must be less than 28MB" });
  }
  const formatVideoTo64 = (file) =>
    parser.format(
      path.extname(file.originalname).toString(),
      file.buffer
    );

  const cloudinaryVideoUpload = (file) =>
    cloudinary.v2.uploader.upload(file, { resource_type: "video" });

  const video64 = formatVideoTo64(video);
  const uploadVideoResult = video
    ? await cloudinaryVideoUpload(video64.content)
    : null;

  const userId = user?.id;

  const newVideo = await Video.create(
    {
      title,
      image: uploadImageResult.url,
      video: uploadVideoResult.url,
      video_id: uploadVideoResult.public_id,
      video_signature: uploadVideoResult.signature,
      description,
      image_id: uploadImageResult.public_id,
      image_signature: uploadImageResult.signature, 
      user_id: userId

} );

  if (!newVideo)
    return res.status(400).json({ message: "Can't add new video" });

  res.status(200).json({
    message: "Video was successfully created",
    newVideo,
  });
} else {
  const userId = user?.id;

  const newVideo = await Video.create(
    {
      title,
      image: uploadImageResult.url,
      description,
      image_id: uploadImageResult.public_id,
      image_signature: uploadImageResult.signature,
      user_id: userId
        },
  );

  if (!newVideo)
    return res.status(400).json({ message: "Can't add new video" });

  return res.status(200).json({
    message: "Video was successfully created",
    newVideo,
  });
}

} else {
res.status(500).json({ message: "HTTP method not valid" });
}
} catch (err) {
return res.status(500).json({
message: "Internal error",
err,
});
} });
export default router.handler({
onError: (err, req, res) => {
console.error(err.stack);
res.status(500).json({ message: Fill in video/image field });
},
onNoMatch: (req, res) => {
res.status(404).json({ message: "Page is not found" });
},
});
`