Upload Multiple Images from your Browser to Cloudinary with React and Express

Upload Multiple Images from your Browser to Cloudinary with React and Express

I was recently tasked with a project implementing a feature that allows users to upload multiple image files at once from their browser to Cloudinary. The general workflow was to send the images to an express.js API endpoint with react and store those images to Cloudinary. This was a little bit tricky and I found few resources that explain this full workflow, so I am writing this article on how you can implement it.

Prerequisites

Before you start with this tutorial make sure you have Nodejs installed. Basic knowledge of React, Nodejs, and Javascript is required.

Setting up our App

Create a new folder and name it according to your preference e.g cloudinary-demo.

Setting up React.js App

Install the react library using npx create-react-app frontend on the terminal

Setting up Express.js App

Create a new folder inside the cloudinary-demo folder called backend. Your folder structure should look like this

Screenshot (99).png

the frontend folder will contain your React.js app and the backend folder will contain your Express.js app, let's navigate to the backend folder and set up our express.js app alongside other packages we will make use of

$ cd backend

$ yarn add Cloudinary cors dotenv express multiparty
  • multiparty will help us parse form data sent from the frontend

  • dotenv will allow us access to environment variables in our application

  • cors lets us perform cross-domain requests.

Implementing the API Endpoint to store images in Cloudinary with Express.js

Step one
Create a Cloudinary account if you don't have one yet here. After creating your Cloudinary account take note of your Cloud Name, API Key, and API Secret on your dashboard

Screenshot (101)_LI.jpg

Step two
Create the following files .env and server.js in the backend folder. In your .env file, input the following credentials there

Screenshot (103)_LI.jpg

Step three
In your server.js file, input the following lines of code

const express = require("express");
const cloudinary = require("cloudinary").v2;
const cors = require("cors");
const multiparty = require("multiparty");
const dotenv = require("dotenv");
dotenv.config();
const app = express();

app.use(express.json());
app.use(cors());

const port = process.env.PORT;

cloudinary.config({
  secure: true,
  cloud_name: process.env.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET,
});

app.listen(port, () => {
  console.log(`Listening at port ${port}`);
});

We imported the different packages we are going to use and passed our cloudinary credentials to cloudinary.config(). Check if your express.js app is running properly by running node server.js in the terminal.

Step four
We will go ahead to implement our API endpoint by adding the following lines of code to the server.js folder.

app.post("/upload", async function (req, res) {
  const urls = [];
  const form = new multiparty.Form({ maxFieldsSize: "20MB" });
  form.parse(req, async function (err, fields, files) {
    const options = {
      use_filename: true,
      unique_filename: false,
      overwrite: true,
      folder: "/test",
    };
    const filesData = fields.file;
    for (let i = 0; i < filesData.length; i++) {
      const imagePath = filesData[i];
      try {
        const result = await cloudinary.uploader.upload(imagePath, options);
        urls.push(result.secure_url);
        if (i === filesData.length - 1 && !!result.secure_url) {
          return res.status(200).json({ data: urls });
        }
      } catch (error) {
        console.error(error);
        return res.status(400);
      }
    }
  });
});

Here multiparty helps us parse the form data we would be receiving from the frontend(browser), we also specify the maximum total file size that will be accepted from the frontend. You can read more about multiparty options here. The options variable contains Cloudinary settings for our file upload including the folder option where we specify the directory we want our images to be stored on Cloudinary, you can read more on that here. We are going to be expecting an array of the multiple files sent from the front end (browser), so we run a for-loop to upload each file to Cloudinary. We wait until the last file has been sent before sending a JSON response which is a list of the URL of the uploaded files.

Sending images from our Browser to the API endpoint with React.js

Go to the frontend folder and run npm run start on the terminal to start our react app. Replace the App.js file with the following lines of code and save.

import { useState } from "react";

function App() {
  const [imagesState, setImagesState] = useState([]);
  const [message, setMessage] = useState("");
  const selectFilesHandler = async (e) => {
    const imagesData = [];
    const files = e.target.files;
    for (let i = 0; i < files.length; i++) {
      imagesData.push(readFileHandler(files[i]));
    }
  };

  const readFileHandler = (file) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = () => {
      setImagesState((curr) => [...curr, reader.result]);
      return reader.result;
    };
  };

  const uploadFilesHandler = async () => {
    setMessage("Uploading...");
    const formData = new FormData();
    for (let i = 0; i < imagesState.length; i++) {
      let file = imagesState[i];
      formData.append("file", file);
    }
    try {
      const res = await fetch("http://localhost:8000/upload", {
        method: "POST",
        body: formData,
      });

      const data = await res.json();
      if (data) {
        setMessage("Done!");
      }
      console.log(data);
    } catch (e) {
      console.log(e);
      setMessage("Error! Could not upload");
    }
  };
  return (
    <>
      <input
        type="file"
        onChange={selectFilesHandler}
        accept="image/*"
        multiple="multiple"
      />
      <button onClick={uploadFilesHandler}>upload</button>
      <p>{message}</p>
    </>
  );
}

export default App;
  • selectFilesHandler function receives all the files selected from the browser

  • readFileHandler function helps us convert every file received from the selectFilesHandler to a base64 encoded data url string. The converted file is then pushed to the imagesState state which is an array

  • uploadFilesHandler function appends all the file data in our imagesState state to the FormData() instance and sends it to our API endpoints.

Testing Our App

Make sure your server.js and React App is running. Your React App should look like this

Screenshot (106).png

  • Click on Choose Files and select multiple image files.

  • After selecting the images of your choice, click on the upload button.

  • Wait until the files have been uploaded, should take a few seconds. You will see a Done! message after the files have been uploaded.

  • Check your browser console for the URL links of the uploaded images.

Screenshot (108).png

Conclusion

So far we have learned how to upload multiple image files at once from our browser to Cloudinary using React and Express. You can apply this logic to your application depending on the use case and can also save the generated URLs to a database. Click here to view the GitHub repo for this implementation

Thanks for reading! I hope this is helpful, your feedback would be appreciated.

Connect with me on Twitter, LinkedIn, Github