Uploading images in your Node.js app using Express and Cloudinary

Uploading images in your Node.js app using Express and Cloudinary

Storing media directly in your database can be considered poor practise as it leads to the poor performance of a system, amongst other issues. To substitute for this, Cloudinary was developed.

Cloudinary is an end-to-end image- and video management solution for websites and mobile apps, covering everything from image and video uploads, storage, manipulations, optimizations to delivery.

In this article, we'll be uploading images to Cloudinary in a node.js/express.js application.

Pre-requisite

  1. Cloudinary account
  2. Node.js installed on your computer
  3. Postman installed on your computer

Cloudinary configuration

Login to your Cloudinary account. On your dashboard are 3 configurations- Cloud name, Api key and Api Secret. Copy these (into a .txt file or sticky notes) as you will need them shortly.

image.png

Install the dependencies and start coding

1) Create a folder to work with. Run npm init -y. This will accept the default config.

2) Install the following dependencies- cloudinary, express, dotenv and express-fileupload

npm install cloudinary express dotenv express-fileupload

3) Create an index.js file which is our starting point, cloudinary.js file to contain the Cloudinary config and upload function, and .env file to contain the environment configs.

4) Copy the Cloudinary configs from your .txt file or sticky note and insert them in the .env file as seen below.

CLOUDINARY_NAME= insert_your_name
CLOUDINARY_API_KEY = insert_your_api_key
CLOUDINARY_API_SECRET = insert_your_api_secret

5) Connect your app to Cloudinary.

// cloudinary.js
const dotenv = require('dotenv');
const cloudinary = require('cloudinary').v2;

dotenv.config();

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET
});

const upload = async (file) => {
  const image = await cloudinary.uploader.upload(
    file,
    (result) => result
  );
  return image;
};

module.exports = { upload };

In lines 6-8, we connected our app to cloudinary.

The upload function that handles uploading the images to cloudinary. It's good practice to have a single function that you can reuse.

You can also upload the images into a specific folder;

const image = await cloudinary.uploader.upload(
    file,
    { folder: 'Test' },
    (result) => result
  );

6) Let's make use of our upload function

// app.js
const express = require('express');
const fileUpload = require("express-fileupload");
const { upload } = require('./cloudinary')

const app = express();
app.use(
    fileUpload({
      useTempFiles: true
    })
);

app.listen(3000, () => {
    console.log('Server listening on port 3000')
})

app.post('/upload', async (req, res)=>{
    if (!req.files) return res.send('Please upload an image');

    const {image} = req.files;
    const cloudFile = await upload(image.tempFilePath);
    console.log(cloudFile)

    res.status(201).json({
        message:'Image uploaded successfully',
        imageUrl:cloudFile.url
    })
})

You can specify the file type that you want to support.

const fileTypes = ['image/jpeg', 'image/png', 'image/jpg'];
if (!fileTypes.includes(image.mimetype)) return res.send('Image formats supported: JPG, PNG, JPEG');

You can also limit the size of the image to be uploaded.

const imageSize = 1024;
if (image.size / 1024 > imageSize) return res.send(`Image size should be less than ${imageSize}kb`);

By default, the image size is in bytes. To convert to kb, divide the image by 1024.

Let's add the 2 options above into our route

app.post('/upload', async (req, res)=>{
if (!req.files) return res.send('Please upload an image')

    const {image} = req.files;
    const fileTypes = ['image/jpeg', 'image/png', 'image/jpg'];
    const imageSize = 1024;    

    if (!fileTypes.includes(image.mimetype)) return res.send('Image formats supported: JPG, PNG, JPEG');  

    if (image.size / 1024 > imageSize) return res.send(`Image size should be less than ${imageSize}kb`);

    const cloudFile = await upload(image.tempFilePath);
    console.log(cloudFile)

    return res.status(201).json({
        message:'Image uploaded successfully',
        imageUrl:cloudFile.url
    })
})

Let's test

Run your app, typing node index.js in the terminal.

Launch Postman and make a POST request with the url- http://127.0.0.1:3000/upload.

We will test with 4 scenarios, trying to upload

1) Without an image image.png

2) A file larger than 1024kb (1MB) image.png

3) A file not of type png, jpg nor jpeg image.png

4) An image less than or equal to 1024kb image.png

If you notice, a new folder called tmp has been created in the root directory. This folder temporarily stores files uploaded. Cloudinary picks up the image via its file path before hosting on its server.

Now, let's head over to Cloudinary and see our image. image.png

Conclusion

Cloudinary is a powerful tool that does much more than what we have covered in this article. I challenge you to go further and explore what more the tool has to offer.

Resources

  1. Node.js SDK

If you like this article, feel free to comment and share. You can also reach out to me on Twitter | LinkedIn | Github

Ciao👋🏼