DEV Community

Cover image for Image Upload to Cloudinary with Nodejs and Dotenv
NJOKU SAMSON EBERE
NJOKU SAMSON EBERE

Posted on • Edited on

Image Upload to Cloudinary with Nodejs and Dotenv

Cloudinary helps developers across the world manage images with minimal efforts. In this tutorial, we will be looking at how to upload images from our application to cloudinary.

This will be a continuation of the last tutorial on setting up a simple, secure and robust server.

You may want to check it out here or you can go ahead and clone the repository. Follow the instructions on README.MD to setup the project on your local machine and then, let's continue on our mission to securely upload images to cloudinary.

Create a Cloudinary Account

  1. To create an account, go to the Cloudinary Website as you can see in the opening image.
  2. Click the sign up button on the top right.
  3. Fill the form that shows up accordingly.
  4. Submit the form using the Create Account button.
  5. Check your email to finish up by validating your email
  6. You should be able to access your dashboard which looks like mine below:

Cloudinary Dashboard

Notice the Account details. It shouldn't be revealed to anyone. I am revealing this to you because this is a temporary account used only for the purpose of this tutorial.

Checkout the Media Library tab too, this is where the uploaded images will appear.

If you have all these showing, then let's rock and roll...

Install Cloudinary in Our Project

If you have not opened your terminal before, now is the time to do so and navigate into the project directory.

Execute the following command to install Cloudinary

  npm install cloudinary --save
Enter fullscreen mode Exit fullscreen mode

Setup Cloudinary in Our Project

  • In the app.js file, require cloudinary below the const app = express(); like so:
  const cloudinary = require('cloudinary').v2
Enter fullscreen mode Exit fullscreen mode
  • Next, add the configuration details from the account details on your dashboard like so:
    cloud_name: 'place your cloud_name here',
    api_key: 'place your api_key here',
    api_secret: 'place your api_secret here',
Enter fullscreen mode Exit fullscreen mode

This is what I have:

  // cloudinary configuration
  cloudinary.config({
    cloud_name: "dunksyqjj",
    api_key: "173989938887513",
    api_secret: "ZPLqvCzRu55MaM1rt-wxJCmkxqU"
  });
Enter fullscreen mode Exit fullscreen mode

Create an API to Upload an Image

  • To avoid bug in our code, First replace the existing API with the following code:
  app.get("/", (request, response) => {
    response.json({ message: "Hey! This is your server response!" });
  });
Enter fullscreen mode Exit fullscreen mode

It is basically the same but this time, we are using get verb in place of the use verb and we added a root end-point (/).

  • Next, just before the module.exports = app; line, we will be creating our image-upload API.

Let's start by placing this code there

// image upload API
app.post("/upload-image", (request, response) => {});
Enter fullscreen mode Exit fullscreen mode

Basically, this is how an API is setup. The API makes a POST request to the server telling the server that the request should be handled with a degree of security. It makes use of two parameters in making this request - anend-point (/upload-image) and a callback function ((request, response) => {}).

Let's breathe life into the API by building out the callback function

Building the callback function

Install body-parser

This npm package enables us to handle incoming requests using req.body or request.body as the case may be. We will be installing body-parser using the following code:

  npm install --save body-parser
Enter fullscreen mode Exit fullscreen mode

Configuring Body-Paser for Our Project

  • Require body-parse in our app.js like so
const bodyParser = require('body-parser');
Enter fullscreen mode Exit fullscreen mode
  • Add the following code to set its json function as global middleware for our app like so:
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));
Enter fullscreen mode Exit fullscreen mode

We can now handle our request body appropriately

Still Building Our Function

  • In the function, add the following code to collect any data (image) entered by a user
    // collected image from a user
    const data = {
        image: request.body.image,
    };
Enter fullscreen mode Exit fullscreen mode
  • Next, upload the image to cloudinary using the following code
cloudinary.uploader.upload(data.image);
Enter fullscreen mode Exit fullscreen mode

Basically, this is all we need to upload our image. So our app.js looks like this :

const express = require("express");
const app = express();
const cloudinary = require("cloudinary").v2;
const bodyParser = require('body-parser');

// body parser configuration
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// cloudinary configuration
cloudinary.config({
  cloud_name: "dunksyqjj",
  api_key: "173989938887513",
  api_secret: "ZPLqvCzRu55MaM1rt-wxJCmkxqU"
});

app.get("/", (request, response) => {
  response.json({ message: "Hey! This is your server response!" });
});

// image upload API
app.post("/image-upload", (request, response) => {
    // collected image from a user
    const data = {
      image: request.body.image,
    }

    // upload image here
    cloudinary.uploader.upload(data.image);

});

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

Now this looks all good and it works perfectly. You can test it out using postman. However, it is going to be awesome if our app can give us feedback when it's done handling our request. Right?

To make this happen, we will add the following then...catch... block to the cloudinary upload like so:

    // upload image here
    cloudinary.uploader.upload(data.image)
    .then((result) => {
      response.status(200).send({
        message: "success",
        result,
      });
    }).catch((error) => {
      response.status(500).send({
        message: "failure",
        error,
      });
    });
Enter fullscreen mode Exit fullscreen mode

So our final code will be:

const express = require("express");
const app = express();
const cloudinary = require("cloudinary").v2;
const bodyParser = require('body-parser');

// body parser configuration
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// cloudinary configuration
cloudinary.config({
  cloud_name: "dunksyqjj",
  api_key: "173989938887513",
  api_secret: "ZPLqvCzRu55MaM1rt-wxJCmkxqU"
});

app.get("/", (request, response) => {
  response.json({ message: "Hey! This is your server response!" });
});

// image upload API
app.post("/image-upload", (request, response) => {
    // collected image from a user
    const data = {
      image: request.body.image,
    }

    // upload image here
    cloudinary.uploader.upload(data.image)
    .then((result) => {
      response.status(200).send({
        message: "success",
        result,
      });
    }).catch((error) => {
      response.status(500).send({
        message: "failure",
        error,
      });
    });

});

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

Testing our API

  • Create a folder/directory in the root directory name it images like so:
  mkdir images
Enter fullscreen mode Exit fullscreen mode
  • Copy an image of your choice to this folder. (Now, the path to your image relative to the app.js file should look like this: "images/<your-image.jpg">)

  • Now let's proceed to postman

    1. In the address bar enter this: http://localhost:3000/image-upload
    2. Set the Header Key to Content-Type and value to application/json
    3. Set the body to the json data we declared in our code like so:
       {
       "image": "images/oskar-yildiz-gy08FXeM2L4-unsplash.jpg"
       }
Enter fullscreen mode Exit fullscreen mode

Hit the Send button and wait for upload to complete and get your response

Postman setup to upload image

Now, this is the result. The image now has a unique public_id which is randomly generated by Cloudinary and a secure_url which is globally accessible (you can load it in your browser to see)

Postman showing result of upload

Finally, checking the Media Library tab on your Cloudinary dashboard, you should have a new image with a new badge on it which has a unique id that matches the public_id we saw in the postman result above just like in the image below

Cloudinary Media Files

Walah!!! We are persisting image without stress... That feels good...

Well, one more thing - SECURITY!

Our Cloudinary configuration details is exposed in our app.js file. If we push our project to github, it becomes publicly available to anyone who cares to check and that becomes a problem if it gets into the wrong hand.

But don't worry about a thing here, there is a fix for almost everything in this space. We will be using the dotenv npm package to hid our configurations from the public.

Secure our Configurations

npm install dotenv --save
Enter fullscreen mode Exit fullscreen mode
  • Require dotenv in app.js like so
  require('dotenv').config()
Enter fullscreen mode Exit fullscreen mode
  • Create a new file in the root directory and name it .env

  • In the file, enter your Cloudinary configuration details like so:

  CLOUD_NAME=dunksyqjj
  API_KEY=173989938887513
  API_SECRET=ZPLqvCzRu55MaM1rt-wxJCmkxqU
Enter fullscreen mode Exit fullscreen mode
  • In the app.js file, we will access the configurations in the .env file via process.env property like so:
// cloudinary configuration
cloudinary.config({
  cloud_name: process.env.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET
});
Enter fullscreen mode Exit fullscreen mode

This is my app.js code at this moment

const express = require("express");
const app = express();
const cloudinary = require("cloudinary").v2;
const bodyParser = require('body-parser');
require('dotenv').config()

// body parser configuration
app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));

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

app.get("/", (request, response, next) => {
  response.json({ message: "Hey! This is your server response!" });
  next();
});

// image upload API
app.post("/image-upload", (request, response) => {
    // collected image from a user
    const data = {
      image: request.body.image,
    }

    // upload image here
    cloudinary.uploader.upload(data.image)
    .then((result) => {
      response.status(200).send({
        message: "success",
        result,
      });
    }).catch((error) => {
      response.status(500).send({
        message: "failure",
        error,
      });
    });
});

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

Let's test our app again to ensure nothing is broken. Here is my result:

Cloudinary media library

I now have two of the same image but with different public_id

And that is it!

Yeeeh!!! Our application is more secure than it was at the onset.

Conclusion

This tutorial was able to take us through the steps involved in uploading an image to cloudinary through a nodejs application.

In the end, we ensure our configuration details is secure by using the dotenv npm package

All codes are available here

Now, after uploading our images to cloudinary through nodejs, it is almost useless if we can not retrieve or use them. For this reason, we will be looking at Persisting and Retrieving images using cloudinary and Postgresql Through Nodejs.

If you have questions, comments or suggestions, please drop them in the comment section.

You can also follow and message me on social media platforms.

Twitter | LinkedIn | Github

Thank You For Your Time.

Top comments (22)

Collapse
 
adybecky profile image
_beckyady

Hi... what if i want to have this part of the code in a separate file

// upload image here
cloudinary.uploader.upload(data.image)
.then((result) => {
response.status(200).send({
message: "success",
result,
});
}).catch((error) => {
response.status(500).send({
message: "failure",
error,
});
});

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

Hey Becky, that is absolutely fine and well recommended especially for big projects.

I did just that in this article

I hope you find the answer there. If you have more questions, I am still available ๐Ÿ˜Š

Collapse
 
dimer191996 profile image
Dimer Bwimba
module.exports.createPost = async (req, res) => {
  let fileName;
  if (req.file) {
    console.log(req.file);
    try {
      if (
        req.file.mimetype != "image/jpg" &&
        req.file.mimetype != "image/png" &&
        req.file.mimetype != "image/jpeg"
      )
        throw new Error("invalid file");
      if (req.file.size > 500000) throw new Error("max size");
    } catch (error) {
      // const errors = uploadErrors(err);
      return res.status(401).send(error);
    }
    console.log(file);
    cloudinary.uploader
      .upload(req.file)
      .then((result) => {
        response.status(200).send({
          message: "success",
          result,
        });
      })
      .catch((error) => {
        response.status(500).send({
          message: "failure",
          error,
        });
      });
Enter fullscreen mode Exit fullscreen mode

this is my image

{
  fieldname: 'file',
  originalname: '0a628080d7386a847d18308ace6d15a6.jpg',  encoding: '7bit',
  mimetype: 'image/jpeg',
  buffer: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 00 48 00 00 ff db 00 43 00 06 04 05 06 05 04 06 06 05 06 07 07 06 08 0a 10 0a 0a 09 09 0a 14 0e 0f 
0c ... 14239 more bytes>,
  size: 14289
}
Enter fullscreen mode Exit fullscreen mode

error:

(node:2016) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Object

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

Hey Dimer, you are sending in an object containing the file details instead of just sending in the path to the image in you local machine.

Check out this dev.to/ebereplenty/cloudinary-and-....

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

The path is supposed to read: "c:/nam/folder/.../file_name.extension" and cloudinary will take it from there

Collapse
 
colourjim profile image
ijele_chimaobi

Please is there a way I can upload a blob, please help me

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

Hey Chimaobi,

Sorry for the late reply

I think you are referring to the frontend of the application. Right?

Collapse
 
colourjim profile image
ijele_chimaobi

I was able to do it on the frontend of the application
I was just asking it were possible for me to do it on the server (nodejs)

Thread Thread
 
ebereplenty profile image
NJOKU SAMSON EBERE

That's alright.

It may be possible but I haven't given it a try before

Thread Thread
 
colourjim profile image
ijele_chimaobi

Okay...
Thanks for time and consign.

Collapse
 
akshay1027 profile image
Akshay.R.R

How to set a particular width and height for the image or reduce image size while uploading? Can you please help me out!

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

I haven't done that before. I think it is doable when delivering the image to a user on the FE. Check this out: cloudinary.com/documentation/image...

Collapse
 
deepak245 profile image
Deepak245

Hi ,

i am facing issue with when parsing data

Collapse
 
tcee42 profile image
Thomas

Thank you Samson, your article helped a lot. Waiting for this "Persisting and Retrieving images using cloudinary and Postgresql Through Nodejs".

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

Hey Thomas, the article is here. I had you in mind when preparing it. Check it out here

Collapse
 
tcee42 profile image
Thomas

Thank you so much Ebere. I'll look at right away.

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

I will definitely work on that especially because you ask. Thank you for reading!

Collapse
 
ndutared profile image
Abby Nduta

Thanks a million. I was totally stuck. Very clear, step by step explanations

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

You are welcome. Comments like this makes me write more. Thanks for reading

Collapse
 
mgrachev profile image
Grachev Mikhail

In addition to using environment variables I can recommend the tool github.com/dotenv-linter/dotenv-li... - itโ€™s a lightning-fast linter forย .env files. Written in Rust.

Collapse
 
ebereplenty profile image
NJOKU SAMSON EBERE

Thank you for that suggestion. I will check it out.

Collapse
 
zerodesu profile image
Ahmad Gani • Edited

thanks for the great tutorial! i have a question, how to manage the image on cloudinary after success uploading the file? i'm confused with usecase in frontend-side