node.jsapimongoosenext.jsrequest-promise

Using Mongoose save() inside Formidable's parse() inside NextJS API


Am using formidable package and mongoose in my NextJS app. So I wrote the API call to allow user to upload a photo along with some data. And I process the files using the formidable and it's working fine. But after processing the file, I need to insert some data to my MongoDB through mongoose and then return the API response. If I use await on the save() method of mongoose to save the data, it throws the error saying the parent needs to be async function. But in my case, the parent is form.parse().

Am a bit confused here on how to solve this issue. I think am confused with Promises here.

Here's the stripped down code of my /pages/api/submit.js :

import dbConnect from '../../lib/dbConnect'
import User from '../../models/User'
import formidable from 'formidable'

export default async function handler(req, res) {
    await dbConnect()

    if (req.method === 'POST') {

        const form = new formidable.IncomingForm();
        // some config
        form.uploadDir = './public/photos/';

        form.parse(req, (err, fields, files) => {
            //.. some logic

            if (err) {
                console.log('error parsing the file')

                return res.status(400).json( {
                    error: true,
                    msg: "Unable to parse the file"
                } )
            }

            // insert some data
            var user = new User( { name: 'blah', file_name: 'x', file_size: 'xx' } );
            //await user.save();
            user.save( err => {
                if( err ){
                    console.log( err )
                    return false
                }

                // success
                res.status(200).json( {
                    error: false,
                    msg: "success"
                } ).end()
            } )
        })
    }
}

Solution

  • Just unwrap it from the callback-hell, so you have a nice async/await code

    👉Live Demo

    
    
    const asyncParse = (req) =>
      new Promise((resolve, reject) => {
        const form = new IncomingForm({ multiples: true });
        form.parse(req, (err, fields, files) => {
          if (err) return reject(err);
          // resolve "returns" the promise so you will have a straighforward logic flow
          resolve({ fields, files });
        });
      });
    
    export default async function handler(req, res) {
      console.log("Receiving");
      if (req.method === "PUT") {
        const result = await asyncParse(req);
        // so you can use it here as a normal code flow
        res.status(200).json({ result });
      }
    }
    

    PS. Why necrobumping? Its one of the first Google results, sorry