Home > Software design >  How to use async await with cloudinary upload API?
How to use async await with cloudinary upload API?

Time:10-10

so below is my API code which receive two image files one containing only one image and other contains 5 images. then I am using a hosting website called cloudinary to upload them and receive a result which includes the URL to the uploaded image. I am trying to push those result into urlArray so later on I can save them to database. However, the code for database executes before everything else. also when I log urlArray at the end . it is just an empty array. I was wondering what am I doing wrong here?

const upload = multer({
  storage: multer.diskStorage({
    destination: "./public/uploads",
    filename: (req, file, cb) => cb(null, file.originalname),
  }),
});

const apiRouter = nc({
  onNoMatch(req, res) {
    res.statusCode(405), json({ error: `method ${req.method} not allowed` });
  },
});

const arrayOfImages = upload.fields([
  { name: "cardImage", maxCount: 1 },
  { name: "images", maxCount: 5 },
]);
apiRouter.post(arrayOfImages, (req, res) => {
  const urlArray = [];
  let cardImage = "";
  const imagesArray = req.files["images"];
  cloudinary.uploader.upload(
    req.files["cardImage"][0].path,
    { folder: "cardImages" },
    async (err, result) => {
      if (err) console.log(err);
      cardImage = result.secure_url;
      console.log(`this is the first call ${cardImage}`);
      fs.unlinkSync(req.files["cardImage"][0].path);
    }
  );
  for (let i = 0; i < imagesArray.length; i  ) {
    cloudinary.uploader.upload(
      imagesArray[i].path,
      { folder: "Images" },
      async (err, result) => {
        if (err) console.log(err);
        urlArray.push(result.secure_url);
        fs.unlinkSync(req.files["images"][i].path);
        // TODO : need to implement the data save to database
      }
    );
  }
  dataBaseConnection();
  const userItem = new Item({
    shortDescription: req.body.shortDescription,
    longDescription: req.body.longDescription,
    price: req.body.itemPrice,
    cardImage: cardImage,
    images: urlArray,
  });
  userItem.save((err) => {
    if (err) console.log(err);
    return console.log("your prodcut has been added to database.");
  });
  console.log(urlArray);
  console.log(`this is the second call ${cardImage}`);

  res.redirect("/dashboard");
});

export default apiRouter;

export const config = {
  api: {
    bodyParser: false, // Disallow body parsing, consume as stream
  },
};

CodePudding user response:

I am not familiar with the coludinary API neither have a run this code, however assuming 'upload' returns a promise ( which it looks like it does) you can just await the results like so:

Note: you may have to inspect the result after await to make sure you are pulling the attribute the right away. I am unfamiliar with the API. But this is the general idea.

Also note that you may have to move you error checking outside to the result object. My example assumes the upload goes through successfully

apiRouter.post(arrayOfImages, async(req, res) => { //<< ---- Notice the async
    const urlArray = [];
    let cardImage = "";
    const imagesArray = req.files["images"];
    
    let result = await cloudinary.uploader.upload( //<<-- NOTE: await here
        req.files["cardImage"][0].path,
        { folder: "cardImages" },
        async (err, result) => {
            if (err) console.log(err);
            fs.unlinkSync(req.files["cardImage"][0].path);
        }
    )
    cardImage = result.secure_url; //<<-- pull out the value you need from result after await

    for (let i = 0; i < imagesArray.length; i  ) {
        let res = await cloudinary.uploader.upload( //<<-- NOTE: await here
            imagesArray[i].path,
            { folder: "Images" },
            async (err, result) => {
                if (err) console.log(err);
                fs.unlinkSync(req.files["images"][i].path);
            }
        );
        urlArray.push(res.secure_url); //<<-- pull out the value you need from result after await
    }

    dataBaseConnection();
    const userItem = new Item({
        shortDescription: req.body.shortDescription,
        longDescription: req.body.longDescription,
        price: req.body.itemPrice,
        cardImage: cardImage,
        images: urlArray,
    });
    userItem.save((err) => {
        if (err) console.log(err);
        return console.log("your prodcut has been added to database.");
    });
    console.log(urlArray);
    console.log(`this is the second call ${cardImage}`);

    res.redirect("/dashboard");
});

So what happened here?

Since the upload function is asynchronous, your code after both the first upload and the loop, execute before the 'upload' actually completes. By using await keyword you can wait for the promise to return.

  • Related