Image Upload to Cloudinary with Nodejs and Dotenv
Tags: cloudinary, node, tutorial, dotenv
Published: 2020-02-07 11:02:45

[Cloudinary](https://cloudinary.com/) 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](https://dev.to/ebereplenty/setting-up-a-simple-secure-and-robust-node-js-server-10n0). 

You may want to check it out [here](https://dev.to/ebereplenty/setting-up-a-simple-secure-and-robust-node-js-server-10n0) or you can go ahead and clone the [repository](https://github.com/EBEREGIT/server-tutorial). Follow the instructions on [README.MD](https://github.com/EBEREGIT/server-tutorial/blob/master/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](https://cloudinary.com/) 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](https://dev-to-uploads.s3.amazonaws.com/i/qfiw7cobdp7pv3c0fb65.JPG)

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``

```javascript
  npm install cloudinary --save
```

### Setup Cloudinary in Our Project
* In the app.js file, require ``cloudinary`` below the ``const app = express();`` like so:

```javascript
  const cloudinary = require('cloudinary').v2
```

* Next, add the configuration details from the account details on your dashboard like so:

```javascript
    cloud_name: 'place your cloud_name here',
    api_key: 'place your api_key here',
    api_secret: 'place your api_secret here',
```

This is what I have:

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

## Create an API to Upload an Image
* To avoid bug in our code, First replace the existing API with the following code:

```javascript
  app.get("/", (request, response) => {
    response.json({ message: "Hey! This is your server response!" });
  });
```
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

```javascript
// image upload API
app.post("/upload-image", (request, response) => {});
```

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 - an``end-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](https://www.npmjs.com/package/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:

```javascript
  npm install --save body-parser
```

### Configuring Body-Paser for Our Project
* Require body-parse in our app.js like so

```javascript
const bodyParser = require('body-parser');
```

* Add the following code to set its ``json`` function as global middleware for our app like so:

```javascript
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));
```

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
```javascript
    // collected image from a user
    const data = {
        image: request.body.image,
    };
```
* Next, upload the image to ``cloudinary`` using the following code
```javascript
cloudinary.uploader.upload(data.image);
```

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

```javascript
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;
```

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:

```javascript
    // 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,
      });
    });
```

So our final code will be:

```javascript
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;
```

### Testing our API
* Create a folder/directory in the root directory name it ``images`` like so:

```javascript
  mkdir images
```

* 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:

```javascript
       {
	   "image": "images/oskar-yildiz-gy08FXeM2L4-unsplash.jpg"
       }
```


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


![Postman setup to upload image](https://dev-to-uploads.s3.amazonaws.com/i/ate77jhmka2agj3nxip2.JPG)


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](https://dev-to-uploads.s3.amazonaws.com/i/wys21hgc58nl4rfmq63i.JPG)


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](https://dev-to-uploads.s3.amazonaws.com/i/vkvevngtumyfdd105suu.JPG)

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
* Install [Dotenv](https://www.npmjs.com/package/dotenv)

```javascript
npm install dotenv --save
```

* Require ``dotenv`` in ``app.js`` like so

```javascript
  require('dotenv').config()
```

* Create a new file in the root directory and name it ``.env``

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

```javascript
  CLOUD_NAME=dunksyqjj
  API_KEY=173989938887513
  API_SECRET=ZPLqvCzRu55MaM1rt-wxJCmkxqU
```

* In the app.js file, we will access the configurations in the ``.env`` file via ``process.env`` property like so:

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

This is my ``app.js`` code at this moment

```javascript
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;
```

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

![Cloudinary media library](https://dev-to-uploads.s3.amazonaws.com/i/d3a2b47shxlmext6o40j.JPG)

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](https://github.com/EBEREGIT/server-tutorial/tree/cloudinary-upload)

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](https://dev.to/ebereplenty/cloudinary-and-postgresql-persisting-and-retrieving-images-using-nodejs-31b2).

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](https://twitter.com/eberetwit) | [LinkedIn](https://www.linkedin.com/in/samson-ebere-njoku-profile/) | [Github](https://github.com/EBEREGIT)**

Thank You For Your Time.