DEV Community

mahiuddinTuhin
mahiuddinTuhin

Posted on

Understanding the File Upload Middleware with Cloudinary in Node.js

In this article, we will explore a middleware for file uploads in a Node.js application, which leverages Cloudinary for image storage. The middleware is written in TypeScript and uses the multer library for handling multipart/form-data, which is primarily used for uploading files.

Setting Up Cloudinary

Cloudinary is a cloud-based service that provides an end-to-end solution for image and video management, including uploads, storage, manipulations, optimizations, and delivery.

The Cloudinary configuration is set up at the beginning of the code:

cloudinary.config({
  cloud_name: config.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET,
});
Enter fullscreen mode Exit fullscreen mode

The cloud_name is your unique Cloudinary account identifier. The api_key and api_secret are your Cloudinary account credentials, which should be kept secure and not exposed in your code.

The Upload Function

The uploadToCloudinary function is responsible for uploading a file to Cloudinary:

const uploadToCloudinary = (path: string, imageName: string) => {
  // ...
};
Enter fullscreen mode Exit fullscreen mode

This function takes two parameters: the local path of the image to be uploaded (path) and the desired public ID for the image on Cloudinary (imageName). If the path is not provided, an error is thrown.

The function returns a Promise that resolves with the result of the upload or rejects with an error. After the upload is complete, the local file is deleted using the fs.unlink function.

Multer Middleware

Multer is a middleware for handling multipart/form-data, which is primarily used for uploading files. It is used to process the incoming request and store the uploaded files in the local filesystem.

The storage object defines where to store the uploaded files and how to name them:

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, process.cwd() + "/uploads/");
  },
  filename: function (req, file, cb) {
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() *  1e9);
    cb(null, file.fieldname + "-" + uniqueSuffix);
  },
});
Enter fullscreen mode Exit fullscreen mode

The destination function determines the folder where the uploaded files will be stored. The filename function generates a unique name for each uploaded file.

Finally, the upload middleware is created using the defined storage:

export const upload = multer({ storage: storage });
Enter fullscreen mode Exit fullscreen mode

This middleware can now be used in an Express route to handle file uploads. When a file is uploaded, it will be stored in the specified directory and then uploaded to Cloudinary.

Code at a glance

/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-var-requires */
import { v2 as cloudinary } from "cloudinary";
import multer from "multer";
import config from "../config";
import AppError from "../errors/customError";
const fs = require("fs");

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

const uploadToCloudinary = (path: string, imageName: string) => {
  if (!path) {
    throw new AppError("File path does not found!", 400);
  }

  return new Promise((resolve, reject) => {
    try {
      cloudinary.uploader.upload(
        path, //local image path
        { public_id: imageName },
        function (error, result) {
          if (error) {
            reject(error);
          }
          resolve(result);

          // removing image file from 'path' of image
          fs.unlink(path, (err: any) => {
            if (err) {
              throw new AppError("Error in deleting file after uploads", 400);
            }
          });
        },
      );
    } catch (error: any) {
      throw new AppError(error.message, 400);
    }
  });
};

export default uploadToCloudinary;

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, process.cwd() + "/uploads/");
  },
  filename: function (req, file, cb) {
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
    cb(null, file.fieldname + "-" + uniqueSuffix);
  },
});

export const upload = multer({ storage: storage });

Enter fullscreen mode Exit fullscreen mode

Conclusion

This middleware provides a robust solution for handling file uploads in a Node.js application. By integrating Cloudinary, it offloads the responsibility of storing and serving images, allowing the application to focus on other tasks. The use of Promises and async/await makes the code easier to read and understand, and the use of multer simplifies the handling of file uploads.

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay