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,
});
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) => {
// ...
};
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);
},
});
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 });
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 });
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.
Top comments (0)