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.