Multer doesn't return req.body and req.file using next-connect

11.6k views Asked by At

I'm using nextjs and I want to upload a file so I used next-connect in order to use multer

import nc from "next-connect";
import multer from "multer";

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

const upload = multer({ dest: `${__dirname}../../public` });

const handler = nc()
  .use(upload.single('image'))
  .post(async (req, res)=>{
    console.log(req.body); // undefined
    console.log(req.file); // undefined
    res.status(200).send("yo");
  })


export default handler;

this is the client side code :

function handleOnSubmit(e){
        e.preventDefault();

        const data = {};

        var formData = new FormData(e.target);
        for (const [name,value] of formData) {
            data[name] = value;
        }
        data.type = data.type[0].toUpperCase();
        data.name = data.name[0].toUpperCase();

        axios({
            method: "POST",
            url:"/api/manager",
            data,
            config: {
                headers: {
                    'content-type': 'multipart/form-data'
                }
            }
        })
        .then(res=>{
            console.log(res);
        })
        .catch(err=>{
            throw err
        });
    }
...
return(
   ...
   <Form onSubmit={(e)=>handleOnSubmit(e)}>
   ...
   </Form>
)

I searched and everything I found was related to nodejs and expressjs but nothing on next.js. I have no idea about how to proceed.

4

There are 4 answers

1
Fatih ATES On

When I switched to the Next.js framework, I first tried to upload a file with the 'multer' library and preferred to give up and use 'formidable'. The reason was that there were a few resources available with Nextjs and multer.

And if I'm not wrong here, multer should be added as middleware, so this means rewriting the server.js page. You can review these topics:

If you don't want to deal with this, you can check out a simple gist on using this resource formidable library: https://gist.github.com/agmm/da47a027f3d73870020a5102388dd820

And this is the file upload script I created: https://github.com/fatiiates/rest-w-nextjs/blob/main/src/assets/lib/user/file/upload.ts

0
ganam On

had the same problem. don't know if it's the same as yours but in case it might help someone .. when I shifted multer to use memory storage rather than desk storage it worked fine .. in my case i was using another middleware after multer to upload to aws s3 so I didn't need to have the file stored in the ./public permanently .. I just needed the req.file available in the next middleware. In your case try changing

const upload = multer({ dest: `${__dirname}../../public` });

to

const storage = multer.memoryStorage()
const upload = multer({storage: storage});
0
Alexander Korostin On

It turned out that all you need is to disable NextJS built-in body parser for the specific API route (https://nextjs.org/docs/api-routes/api-middlewares#custom-config):

// The following should be exported from your API route file
export const config = {
  api: { bodyParser: false },
};
2
Jerome On

for those who are still looking for a solution on how to use multer as middleware with nextJs, here is an example of an API route, using multer has middleware. The route is calling a getSignedUrl function to upload file to bucket.

running nextJs v12 and multer 1.4.3

import multer from "multer";
import { NextApiRequest, NextApiResponse } from "next";
import { getSignedUrl } from "../../lib/uploadingToBucket";

function runMiddleware(
  req: NextApiRequest & { [key: string]: any },
  res: NextApiResponse,
  fn: (...args: any[]) => void
): Promise<any> {
  return new Promise((resolve, reject) => {
    fn(req, res, (result: any) => {
      if (result instanceof Error) {
        return reject(result);
      }

      return resolve(result);
    });
  });
}

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

const handler = async (
  req: NextApiRequest & { [key: string]: any },
  res: NextApiResponse
): Promise<void> => {
  //const multerStorage = multer.memoryStorage();
  const multerUpload = multer({ dest: "uploads/" });

  await runMiddleware(req, res, multerUpload.single("file"));
  const file = req.file;
  const others = req.body;
  const signedUrl = await getSignedUrl(others.bucketName, file.filename);
   res.status(200).json({ getSignedUrl: signedUrl });
};

export default handler;