Image upload with Cloudinary, NodeJS & Mongoose
Today I'd like to share my experience on how to upload an image in a NodeJS project using Cloudinary to host the image, Mongoose(MongoDB) to store the link of the hosted image, and Postman to upload the image.
To get started, create/sign into your Cloudinary account, we will need to get the API keys for configuration.
I am assuming you have some basic understanding of NodeJS and Mongoose. The example application takes a blog post information which includes an image.
To get started, you need to install the below packages in your node app.
npm install cloudinary multer multer-storage-cloudinary
The Cloudinary Node SDK allows you to quickly and easily integrate your application with Cloudinary. Effortlessly optimize, transform, upload and manage your cloud's assets. npm link
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. npm link
Grab your API key, Cloud Name, and API Secret from the Cloudinary dashboard (see sample image above), and add them to your .env file
CLOUDINARY_CLOUD_NAME=<your_cloud_name> CLOUDINARY_API_KEY=<your_api_key> CLOUDINARY_API_SECRET=<your_api_secret>
In the root directory (same level as the main app) create a config folder which will hold our configuration files then create a file cloudinaryConfig.js
and paste the below code
const cloudinary = require('cloudinary').v2; const dotenv=require('dotenv'); dotenv.config(); cloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET })
The above code is importing and configuring Cloudinary SDK with the API credentials we set up in our .env
With our Cloudinary configuration out of the way, now we need to configure multer. in the config folder create multer.js
and paste the below code
const multer = require("multer"); const cloudinary = require("cloudinary").v2; const { CloudinaryStorage } = require('multer-storage-cloudinary'); const storage = new CloudinaryStorage({ cloudinary: cloudinary, params: { folder: 'mernBlogImages', format: async (req, file) => 'png', // supports promises as well }, }); module.exports = multer({storage: storage});
The above is configuring the multer engine with the Cloudinary configuration we setup earlier, the folder value ('mernBlogImages') in the params can be any name you wish. If the folder does not exist it will be created automatically in Cloudinary and that is where the images will be hosted. Note that all parameters are optional except the configured Cloudinary API object See their Readme. Lastly, we are telling multer where our images should be kept and exporting multer to use it as a middleware in our addPost route.
With all the configuration out of the way, we can now use the multer middleware we exported from multer.js
in the endpoint handling the image, in our case that will be the add-post
See the code below:
const express = require('express'); const router = express.Router(); const postsController = require('../controllers/postsController') require("../config/cloudinary.config"); const upload = require("../config/multer"); router.post('/add-post', upload.single("image"), postsController.addPost) module.exports = router
The upload middleware will take the image and upload it to Cloudinary then return req.file object containing the file information which includes the path to our hosted image in Cloudinary which can be accessed in the route with req.file.path
It is worth noting that we have to indicate that we are going to upload only one image at a time.
The 'image' string passed to the upload middleware needs to match the filed name from the form. It tells multer which field on the request it should look for the file in. If these fields aren't the same in the HTML form and on your server, your upload will fail See their Readme
The controller function handling add-post
exports.addPost = async (req,res,next)=>{ const {title,content,status} = req.body if(!title || !content || !status){ throw new BadRequestError('Please provide all values') } console.log(req.file) //log of the req.file // { // fieldname: 'image', // originalname: 'dog.jpg', // encoding: '7bit', // mimetype: 'image/jpeg', // path: 'https://res.cloudinary.com/docrd9dcy/image/upload/v1678715008/mernBlogImages/av5fgsv6brqmhcxdiqbk.png', // size: 1346123, // filename: 'mernBlogImages/av5fgsv6brqmhcxdiqbk' // } const post = await Post.create({title,content,status,imagePath: req.file.path }) res.status(StatusCodes.CREATED).json(post) }
Finally our API is ready to be tested, I am going to use Postman to send a request to our endpoint postman
After sending the request, go to Cloudinary Media Library and click the image folder you defined in the Cloudinary configuration, in our case it will be mernBlogImages Snap of the post on MongoDB:
Thanks for reading, I hope this is helpful!