Progress with Cloudinary
Tags: opensource, cloud, javascript, programming
Published: 2023-12-13 03:22:15

In my [last post](https://dev.to/amnish04/planning-for-a-contribution-55i9), I discussed about **my plan** for integrating cloud storage into an open-source project.

If you haven't read that yet, please take a moment to go through it first before continuing.

In this post, I'll share my **progress** in executing that plan and any realizations that emerged along the way.

## Table of Contents
&nbsp;1. [Researching Cloudinary ☁️](#researching-cloudinary)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1. [Exploring the SDK 🧰](#exploring-the-sdk)
&nbsp;2. [Observing Existing Code 🧐](#observing-existing-code)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2. [UI 💻](#ui)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.3. [Server Code 🖥️](#server-code)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.4. [Back to UI code](#back-to-ui-code)
&nbsp;3. [Changes Needed](#changes-needed)
&nbsp;4. [Conclusion 🎇](#conclusion)

## Researching Cloudinary ☁️

As per my [plan](https://dev.to/amnish04/planning-for-a-contribution-55i9#the-plan), the first thing I had to do was research a bit more about [Cloudinary](https://cloudinary.com/ip/gr-sea-gg-brand-home-base?utm_source=google&utm_medium=search&utm_campaign=goog_selfserve_brand_wk22_replicate_core_branded_keyword&utm_term=1329&campaignid=18164753405&adgroupid=144188713167&keyword=cloudinary&device=c&matchtype=e&adposition=&gad_source=1&gclid=CjwKCAiApuCrBhAuEiwA8VJ6JqrOIBOzPcmSFqCmA3LlgRTBDJKlppcBMVQFOrzZLVGx2aoIu4CTIhoCur8QAvD_BwE) and how such [cloud services](https://www.citrix.com/solutions/digital-workspace/what-is-a-cloud-service.html) can be consumed by the applications.

### Exploring the SDK 🧰

I started out by looking at the [getting started](https://console.cloudinary.com/console/c-d620f47df8cc81ff203b13c32ccfd1/getting-started) page in the **official documentation**, where it was shown how to install **Cloudinary** [SDK](https://www.techtarget.com/whatis/definition/software-developers-kit-SDK#:~:text=A%20software%20development%20kit%20(SDK)%20is%20a%20set%20of%20software,build%20applications%20for%20specific%20platforms.) (Software Development Kit), and configure it for various programming languages/frameworks.

![Setting up Cloudinary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vre2mrkt7gpiqdgq0uzq.png)

For me, since I had to set up in a [Node](https://nodejs.org/en) project, I installed it using [npm](https://www.npmjs.com/).

```
npm install cloudinary
```

And to test if I am able to configure the SDK, I pasted the following boilerplate right before the server starts listening.

```ts
// Configure Cloudinary with your credentials
cloudinary.v2.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});
```

As you can see, I also had to setup my credentials as environment variables, so the maintainer could **easily swap** them with his own account as I won't own the data.

```
# Cloudinary Secrets
CLOUDINARY_CLOUD_NAME=get-your-own
CLOUDINARY_API_KEY=get-your-own
CLOUDINARY_API_SECRET=get-your-own
```

Once you **sign up** for an account, the above credentials can be found on the **dashboard** page.

![Cloudinary Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myjrlpub76m2u9b6ed43.png)

But I still had no idea if it worked, and the only way to know was trying to **upload** a test image to my **media library**.

As I scrolled a bit in the documentation, they gave me a demo for exactly that.

![Upload First Image SDK Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3z1jni233l3ubmdmi5lv.png)

Referencing the documentation, I tried to upload a sample asset right after the code to configure cloudinary like so.

```js
// Configure Cloudinary with your credentials
cloudinary.v2.config({
  cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

// Upload Your First Asset
cloudinary.v2.uploader.upload(
  "https://upload.wikimedia.org/wikipedia/commons/a/ae/Olympic_flag.jpg",
  { public_id: "olympic_flag" }, 
  function(error, result) {console.log(result); }
);
```

Now as soon as I started the server,

```
npm start
```

I saw the following **logs** printed in my console.

![First Upload Success](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/necipb9xvjnlh4x14g2d.png)

and in the media library,

![First Uploaded Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zy1ej9q0gvw2choytbt3.png)

Which means my upload was a **success**, yayy 🎉

This might not seem like something worth celebrating, but ever since I started working on this, I had a doubt at the back of my head if I would be able to make it happen.

This little success **relieved** a lot of **stress** from my ❤️, and gave me confidence to **keep going**.

## Observing Existing Code 🧐

Now that I knew that I could upload the images as expected, it was time to look at the **existing logic** that had to be modified to use **Cloudinary**. 

### UI 💻

I started by looking at the UI code, that was sending the images to the server using forms.
I could only recall 2 places where images were being uploaded, **user registration** and **posts**.

Starting with user registration felt like a good idea.

I found the `register` function and noticed the pattern the owner was using to handle uploads.

![Register Function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dsazdarfkucxk4j3nzk9.png)

The `picture` property was a [File](https://developer.mozilla.org/en-US/docs/Web/API/File) object, that was captured from the **file upload** input control.

![File upload dropzone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0rwxvqlrwrtprd9b6d7.png)

What I noticed was that apart from sending the normal form data in the request, the owner was also sending an additional property called `picturePath` which was basically the `name` of the **image file** being uploaded.

### Server Code 🖥️

Now that I knew what was being **sent**, I had to see how it was being **received** and **handled** on the server.

I opened `index.js`, the entry point of the server code, and found that any image uploads were being stored in the server's **disk storage** using a very popular library named [multer](https://www.npmjs.com/package/multer).

![Multer Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jsl5hws7vkstybkqwpoq.png)

From the official [documentation](https://www.npmjs.com/package/multer),
> Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.

The files were being saved using their **original name** as defined in the `upload` middleware **configuration**, which explains why another property `picturePath` was being stored with the `user` data - to be able to request it back using the same name.

### Back to UI code

The last thing I had to see was how the **saved image** data was being requested back in **UI**.

[**UserImage.jsx**](https://github.com/danielmarv/ChatRoom/blob/main/client/src/components/UserImage.jsx)
```jsx
import { Box } from "@mui/material";

const UserImage = ({ image, size = "60px" }) => {
  return (
    <Box width={size} height={size}>
      <img
        style={{ objectFit: "cover", borderRadius: "50%" }}
        width={size}
        height={size}
        alt="user"
        src={`https://chatroomapi-v1.onrender.com/assets/${image}`}
      />
    </Box>
  );
};

export default UserImage;
```

As expected, it was being requested from the **local storage** of server using the `picturePath` that was saved in user data.

## Changes Needed

It took me a while to understand existing code, but now I it was time to decide what changes had to be made.

This is what I have in mind.

**1.** I'll have to come up with a way to store the uploaded images temporarily in **memory**, before finally uploading to **cloudinary**.
**2.** Instead of saving the **file name** in `picturePath` property, I should be storing the `uri` of the file uploaded to **cloudinary**.
**3.** When requesting images back in **UI**, I need to directly use the `picturePath` as `src`, which would be the **exact location** of images.

## Conclusion 🎇

Now that I understand what's the current logic of **image uploads**, and how to use the [Cloudinary SDK](https://console.cloudinary.com/console/c-d620f47df8cc81ff203b13c32ccfd1/getting-started), it is time to get to work and get it done 🐱‍💻

I'll be following up with a final blog for this series, once I have successfully integrated **cloudinary** with [the project](https://github.com/danielmarv/ChatRoom/tree/main).

**Stay Tuned 😎**