DEV Community

Cover image for How To Upload Multiple files to Cloudinary in Nodejs using Promise.all
Olanrewaju A. Olaboye
Olanrewaju A. Olaboye

Posted on

How To Upload Multiple files to Cloudinary in Nodejs using Promise.all

It has remained something confusing while perusing cloudinary documentation on how exactly do you upload multiple images, for most developers what they tend to do is to call the single file upload method on the SDK in a loop, while this seems to work at times it gets buggy when one of the files has to take more time than the other because of the size. To follow along the tutorial you can download the starter boilerplate nodejs with express code from Github .

We need to add multer configuration to our server.js file, then use this to create an. upload middleware function.

First Acts

//clone the repo
git clone https://github.com/wonderfulolanrewaju/multi-file-uploader/blob/master/package.json

//cd into the project
cd multi-file-uploader

//install all dependencies
yarn install

//install nodemon for server restart on save
yarn add -D nodemon

//install new dependencies
yarn add dotenv
Enter fullscreen mode Exit fullscreen mode

Second Acts

//Add the following object to your package.json
//What this does is allow us to make our server restart on save and run our js file with Esm module so we can use import syntax

 "scripts": {
    "start": "node -r esm server.js",
    "dev: "nodemon -r esm server.js"
  },
Enter fullscreen mode Exit fullscreen mode

Third Acts: Change the top part of server.js

import express from "express";
import cloudinary from "cloudinary";
import multer from "multer";
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const {
  NODE_ENV,
  PORT: productionPort,
  IP: productionIP,
  cloudinaryName,
  cloudinaryApiKey,
  cloudinaryApiSecret,
} = process.env;
const storage = multer.diskStorage({
  filename: function (req, file, cb) {
    cb(null, file.fieldname + "-" + Date.now());
  },
});

cloudinary.v2.config({
  cloud_name: cloudinaryName,
  api_key: cloudinaryApiKey,
  api_secret: cloudinaryApiSecret,
});

const upload = multer({ storage });

app.get("/", (req, res) => {
  return res.status(200).json({
    message: "Multiple uploader api",
  });
});

...
if (NODE_ENV === "production") {
...

Enter fullscreen mode Exit fullscreen mode

Acts Four
What we do next is used the upload middleware function created from multer, this middleware's array method : "upload.array(nameOfFilesFields, maxCount)" takes the name we want to call the file field and the maximum number of images it should allow for upload.

app.post("/images", upload.array("pictures", 10), async (req, res) => {
  try {
    let pictureFiles = req.files;
    //Check if files exist
    if (!pictureFiles)
      return res.status(400).json({ message: "No picture attached!" });
    //map through images and create a promise array using cloudinary upload function
    let multiplePicturePromise = pictureFiles.map((picture) =>
      cloudinary.v2.uploader.upload(picture.path)
    );
    // await all the cloudinary upload functions in promise.all, exactly where the magic happens
    **let imageResponses = await Promise.all(multiplePicturePromise);**
    res.status(200).json({ images: imageResponses });
  } catch (err) {
    res.status(500).json({
      message: err.message,
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

You can run yarn dev. your app should be running on localhost:9000

You can make a request to http://localhost9000/images with the form-data request body type using pictures as field name a sample screenshot is shown below
Response screenshot
You can also view the sample response json on a Public directory

The completed version of the code is available on Completed branch on Github and live version available on Heroku.

Discussion (2)

Collapse
khauri profile image
Khauri • Edited on

Nice tutorial. Very succinct.

I had to solve a similar problem like this, except with uploading images to AWS S3. I discovered pretty quickly that uploading assets to our server and then sending them elsewhere had a tendency to run the server out of memory/disk space and cause the app to crash or eat up the event loop and cause a lot of latency. In the end we settled on doing client-side uploads straight to S3 by using a signed URL. I believe Cloudinary has something similar. I believe they have an api here for allowing multiple images as well.
Would love to see your take on this.

Collapse
boyepanthera profile image
Olanrewaju A. Olaboye Author

Thanks, @khauri you are very right. But there are few ways to handle that load issue. One is to make the response event-based using socket rather than HTTP req/res circle. And I agree with you there are times when you just give the frontend the keys and a chance to use the React/Vue SDK and they only send a reference to the upload secure_url and public key to the server which I believe was your go-to way.