In today’s online world, the delivery speed of your eCommerce web and mobile apps is a paramount factor in user experience. If your customers become frustrated by a lengthy load time for your website, they might stop visiting it, putting your online presence at risk. The fact is, people judge your brand by how well they can interact with your web and mobile apps before contacting you in person.
For web developers, managing digital assets, such as videos, photos, music, and other multimedia, is a must-do. Poor handling of that task might lead to slow performance of your apps, causing a dismal user experience.
No worries,Cloudinary is here to the rescue.
Cloudinary is a cloud-based platform for managing images and videos, enabling businesses and developers to focus on their specialties. In fact, management of digital assets is Cloudinary’s core business.
This article steps you through the process of developing a simple, web-based app that creates, reads, and deletes media from the Cloudinary servers.
Installing NPM
To start, download the most stable release of the Node.js binaries from https://nodejs.org
.Afterwards, install them on your machine by following the procedure on the page that pertains to your platform.
To confirm the installation, type these two commands:
node -v
npm -v
The output displays the version numbers of your Node.js and the Node Package Manager (NPM), a tool for installing, uninstalling, and maintaining package modules for apps.
Initializing a New App
A basic Node app contains a .js
file and a package.json
file, which does the following :
- Specifies the packages on which your project depends,
- Lists the versions of a package that your project can use according to the
semantic versioning
rules. - Makes your build reproducible, hence easier to share with other developers.
To generate a package.json
file for your app, navigate to your project folder in a terminal or, for Windows users, in Git Bash, and type the following command:
npm init -y
Running the above command without the flag -y
generates questions that prompt for answers from you, which would clearly describe the app and its dependencies.
Installing the Required Dependencies
Run this command to install the required dependencies:
npm install express body-parser multer express-handlebars moment dotenv cloudinary --save
Below are the dependencies:
-
express
: A web-app framework for Node.js. -
body-parser
: A middleware that handles post requests inexpress
. -
multer
: The Node.js middleware for handling multipartFormData
. -
express-handlebars
: A Handlebars view-engine forexpress
. moment
: A lightweight JavaScript date-library for parsing, validating, manipulating, and formatting dates.dotenv
: A module that loads environment variables from a.env
file into theprocess.env
property.cloudinary
: A Node.js wrapper that enables you to communicate with the Cloudinary servers.
Once the dependency packages are in place, edit thepackage.json
file to read like this:
As specified in the file, the entry point to your app is the server.js
file. That is where you will document most of the logic on which the app depends.
Starting the Server
Next, start the server by adding the following code to the server.js
file:
const express = require("express");
Server running on ${PORT}
const app = express();
app.get("/", (req, res) => res.send("Hello Cloudy"));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log();
});
Aftwards, start your app by running this command:
node server.js
Now go to localhost:5000
on your browser to verify that the string Hello Cloudy
is displayed.
Building the Project Structure
express-handlebars
is your default templating engine on the front end. To make use of it, do the following:
- Register the templating engine’s packages by adding the following code to your
server.js
file:
const exphbs = require('express-handlebars');
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
2.Enclose all the front-end files in a folder called views
.
- In the
views
folder, create another folder and name itlayouts
, in which themain.handlebars
file, which contains your app’s front-end structure, resides.
Your app’s project structure now looks like this:
Adding Content to the main.js
and index.handlebars
Files
Add the following code to the main.js
file:
With the Moustache symbol {{body}}
, you can seamlessly invoke other pages into the main body.
Next, go to the root of the views
folder, create an index.handlebars
file, and then add a media-upload form with the following code to the file:
Afterwards, run the app on localhost:5000
on the browser and verify that the form below is displayed:
Configuring Multer
Recall that you installed Multer earlier. That’s a Node.js middleware for uploading or handling multipart FormData
.
To configure Multer:
- In the root of your app, create a folder called
handlers
for storing the configurations for Multer and other packages. - In the
handlers
folder, create a file calledmulter.js
with this configuration code:
const multer = require("multer");module.exports = multer({
storage: multer.diskStorage({}),
fileFilter: (req, file, cb) => {
if (!file.mimetype.match(/jpe|jpeg|png|gif$i/)) {
cb(new Error("File is not supported"), false);
return;
}cb(null, true);
}
});
Next, export multer.js
to the main server.js
file by adding this codeline to server.js
:
const upload = require("./handlers/multer");
Then edit the upload route to read like this:
app.post("/uploads", upload.single("image"), (req, res) => {res.send(req.file);});
The above steps ensure that when you upload a media file, you can capture the content of the request on the /uploads
route, as shown here:
Uploading Media to Cloudinary
The project is now ready for file uploads to Cloudinary. Perform the steps below.
Initializing the Cloudinary SDK
First, initialize the Cloudinary SDK into the project by adding this codeline to the main server.js
file:
const cloudinary = require("cloudinary");
Storing and Securing Cloudinary API Keys
To use Cloudinary, you must store its API key, cloud name, and cloud secret in your app. Those keys identify the app or user who’s accessing the Cloudinary servers.
Secure the keys with the dotenv
package. Even though you can store and use keys without packages, the packages are of great help in managing the keys.
To prepare dotenv
for use:
- Add these two lines to your
server.js
file:
require("dotenv").config();
require("./handlers/cloudinary");
The second codeline above calls for a cloudinary.js
file in the handlers
folder.
2.Create a cloudinary.js
file in the handlers
folder with the following content:
const cloudinary = require("cloudinary");
cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_ID,
api_secret: process.env.API_SECRET
});
With this file, the app can locate your server’s access keys that are stored in the .env
file.
3.Go to the root of the app and create the .env
file.
If your .env
file contains confidential values, such as keys, secrets, and passwords, place it in the .gitignore
folder to prevent it from being committed it to the GitHub repository.
Afterwards, declare your credentials in the .env
file by adding the following code to it:
CLOUD_NAME= your_cloud_name
API_ID= id
API_SECRET= secret
To get the values for those three credentials, first register for a Cloudinary account. Once you are logged in, you’ll see the credential values on your Dashboard. Here’s an example:
Configuring the /Uploads
Route
For details on how to perform create, read, update, and delete (CRUD) operations to and from the Cloudinary servers, see the related documentation.
To enable file uploads, configure the post “/uploads”
route, like this:
`app.post("/uploads", upload.single("image"), async (req, res) => {
const result = await cloudinary.v2.uploader.upload(req.file.path);
res.send(result);
});`
With that configuration, Cloudinary would store the media files that you submit and return to you an object that spells out the properties of those files. See the example below.
Setting Up the Cloudinary Upload Widget
In case you worry that uploading media to the Cloudinary servers might take up an inordinate amount of time, worry no more. Cloudinary’s -upload widget renders file uploads a fast process. For details of the widget, see the related documentation.
Follow these steps to set up the upload widget:
- Add a button to your form with the value of the ID (
id
) specified asupload_widget_opener
, like this:
<input value="Upload with Cloudinary Widget" id="upload_widget_opener"
class="btn btn-primary btn-block">
- Add this script to the
main.handlebars
file to load the widget:
<script src="//widget.cloudinary.com/global/all.js" type="text/javascript">
</script>
- Set up a handler to listen to a click event of the button element on the web page and then call the widget's
open
method to display the initialized widget. Below is the sample code.
Finally, change your upload presets from signed to unsigned. To do so, choose Settings > Upload Tab > Upload Presets and make the change in the dialog box that is displayed.
You can now upload media with Cloudinary’s upload widget.
Retrieving Stored Media From Cloudinary in JSON Format
In the server.js
file, define a GET “/api/files”
endpoint to call all the files you have stored in Cloudinary. Add the following code:
app.get("/api/files", async (req, res) => {
const images = await cloudinary.v2.api.resources({
type: "upload",
prefix: "image"
});
return res.json(images);
});
Afterwards, go to localhost:5000/api/ files on your browser for a display of all your stored files in Cloudinary.
Displaying Your Stored Files on the Front End
To display your stored files on the front end, send a GET request to the Cloudinary storage, which will then return an object with all the stored data for conversion into a format that suits the app. For this app, target the secure_url
and created_at
fields.
Create another endpoint in your server.js
file with the following format:
app.get("/files", async (req, res) => {
const images = await cloudinary.v2.api.resources({
type: "upload",
prefix: "image"
});
// Check if files
if (!images || images.length === 0) {
return res.status(404).json({
err: "No files exist"
});
}
// Files exist
res.render("files", {
images: images
});
});
You can now render all the media on the /files
route on the browser. However, for that to happen, you must first create the endpoint in the views
folder and add logic to it to loop and format the responses you receive.
In the views
folder, create a files.handlebars
file with the following code:
Recall that you’re targeting the url
and created_at
endpoints from the server. The code above displays all your media by means of bootstrap cards after looping through the media with the Handlebars’ looping technique.
You’ll now see the following response when you access the route:
Deleting Files
You can easily delete a media file by passing its ID (id
) in a request, as shown in this example:
app.delete("/files", (req, res) => {
let id = req.body.id;
cloudinary.v2.api.delete_resources([id], function(error, result) {console.log(result);});
});
By setting cloudinary.v2.api.delete_resource(), you can capture the ID of the selected media file and delete that file from Cloudinary.
Earlier, on the bootstrap card, you added a button to initiate the delete operation when clicked. Complete that setup by adding the following script under the bootstrap card on the files.handlebars
route:
<script>
/files
deleteImage = () => {
const imageClickedID = event.target.id
fetch(, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: imageClickedID })
})
.then(location.reload())
.catch(err => console.log(err))
}
</script>
There! Now you can delete the selected file from Cloudinary by clicking the Delete button.
Formatting the Date With Moment.Js
The only remaining task is to set up the date and time in a readable format. Do that with a package called moment
, a lightweight JavaScript date-library for parsing, validating, manipulating, and formatting dates.
You’ve already pulled the package to the project. Now do the following:
Initialize moment
into the project with this codeline:
const moment = require("moment");
Call the moment
variable for the date-format values by navigating to the line in which you declared your default layout and adding a helper` function:
helpers: {
renderDateFormat: function(time) {
return moment(time).format("MMMM Do YYYY");}
}
Open the files.handlebar
file and add renderDateFormat
within the Handlebars
created_at` helper. Your helper then reads like this:
{{renderDateFormat created_at}}
Your app is now all set, resembling the one hosted on Heroku.
Checking Out the References
Managing digital media with Express, Multer, and Cloudinary is a painless, seamless, and simple process. In particular, Cloudinary’s robust features greatly accelerate software development that involves digital media. The Cloudinary documentation contains all the details.
Additionally, feel free to clone and modify the source code on GitHub. Have fun!
Top comments (1)
Hi, how do you upload multiple images with multer and save to cloudinary?