How to upload images and videos to Cloudinary using Node.js

  • How to upload images and videos to Cloudinary using Node.js

    Sharing is Caring... Show some love :)

    How to upload images and videos to Cloudinary using Node.js from our frontend can be a challenging task for beginners.

    In this article, we all are going to learn one of the most fundamental and crucial features in any web/mobile application.

    We learn how to upload images and videos to Cloudinary using node.js and also save it in our local server using best practice and industry standards.

    We will discuss useful packages that make our development process easier and faster, and we are also going to learn how to connect our server to the Cloudinary CDN for storing images and videos sent from our server.

    PREREQUISITE

    • Any IDE of your choice.
    • Fundamental knowledge of JavaScript and it’s runtime environment Node.js.
    • A Cloudinary account.
    • POSTMAN for testing our API.
    • MongoDB for storing the data of our files.
    • And of course a basic knowledge of software development.

    So let us quickly get started.

    Setting up a new project with expressjs.


    Firstly, you will need to create a folder named fileUpload in any desired directory of your choice.

    Well, I’m using my desktop directory for this process.

    [[email protected] Desktop]$ mkdir fileUpload

    Then you change the directory to the newly created folder directory and create your entry file.

    [[email protected] fileUpload]$  touch app.js

    Now that your entry file has been created, we are going to start writing the necessary code to handle the file upload process to the Cloudinary server.

    But before that, you will need to install some vital packages that will help to make the development faster. These packages include:

    • Express.js
    • Cloudinary
    • Multer
    • Mongoose
    • Path

    We can install all these by writing the following code in the terminal of our project directory.

    npm install express cloudinary multer mongoose path dotenv --save

    After a successful installation, we can now go ahead and start writing the code for the server setup.

    In the app.js file, you can write the below codes to set up the server.

    
    const express = require('express'),
          app = express(),
          PORT = 3000;
    app.get('/server',(req,res)=>{
      res.send('Server seems to be working')
    }).listen(PORT, ()=>{
      console.log(`Server is running on ${PORT}`);
    })

    In the project directory, we can start the server by running node app in the terminal.

    We are good to go if we see on our terminal:

    Server is running on 3000

    To verify we can easily go to our browser and check, by going to http://localhost:3000/server, if it matches what we have below or whatever message you displayed then it is working fine.

    s 0D5A2B7AF5CBEAD9E1F8069E1D7D47060C5A67BEE2E7F0FACD6B1526B892E5A9 1599392147396 Screenshot 2020 09 06 12 35 32 - How to upload images and videos to Cloudinary using Node.js

    Alright, we can go ahead and complete the code to implement our first feature.

    Creating your routes

    In the app.js file, we are going to create an endpoint that will be used to post the images that are going to be sent to the cloudinary server.

    
    const express = require('express'),
          app = express(),
          PORT = 3000;
    app.get('/server',(req,res)=>{
        res.send('Server seems to be working') 
    });
    app.post('/postImage',(req,res)=>{
      res.send('Images posted successfully')
    }).listen(PORT, ()=>{console.log(`Server is running on ${PORT}`)})

    Now that a post route has been created, we are going to implement the logic for handling that route.

    Upload Image to Cloudinary using node.js

    Create your Image models

    We are going to create 4 folders called controllers, routes, config, models.

    In your project directory:

    [[email protected] fileUpload]$  mkdir routes controllers config models

    Change directory to the model’s folder and create a new file called imageModel.js.

    This file is going to contain the logic of how each image file data is going to be stored on our database.

    Inside the file you can write these codes:

    
    const mongoose = require('mongoose'),
          {Schema} = mongoose,
          imageSchema = new Schema({
            imageName: {
              type: String,
              required: true
              },
            imageId: {
              type: String,
              },
            imageUrl: {
              type: String,
            }
         });
    
    module.exports = mongoose.model("Image", imageSchema)

    Now that the imageSchema has been set up, we can now go and set the configuration file for cloudinary.

    ALSO READ  Laravel Tutorial: The Ultimate Guide (2021)

    Configure Cloudinary

    Before we do that, we need to login to our Cloudinary account at https://cloudinary.com/users/login and grab our Cloud name, API Key, and API secret.

    Those credentials are needed in order for us to have access to our Cloudinary resources such as the images and videos stored in our account.

    Now that you have those details, go to the config folder and create a file called cloudinaryConfig.js.

    
    require("dotenv").config();
    const cloudinary = require("cloudinary");
    cloudinary.config({
      cloud_name: process.env.CLOUD_NAME || YOUR_CLOUD_NAME,
      api_key: process.env.API_KEY || YOUR_API_KEY,
      api_secret: process.env.API_SECRET || YOUR_API_SECRET,
    });
    exports.uploads = (file) => {
      return new Promise((resolve) => {
        cloudinary.uploader.upload(
          file,
          (result) => {
            resolve({ url: result.url, id: result.public_id });
          },
          { resource_type: "auto" }
        );
      });
    };

    N/B: Replace YOUR_CLOUD_NAME with the actual cloud name from Cloudinary and API_KEY with your actual API key from Cloudinary the same with API_SECRET.

    To explain these few lines of code, we made a Cloudinary config file that contained our credentials in order to post images and videos to the Cloudinary server and we also exported a function called uploads.

    This function takes in a parameter called file (your image/video file) and uploads it with the uploader.upload() method from the Cloudinary package.

    We made the function return a new Promise object that would contain the resolved object which is our uploaded file url and the id of the file.

    Building the upload logic

    Now let us go to our controllers and fix things up over there.

    In our controllers, we are going to create an Error handler firstly.

    Then go ahead to wrap our imageController.

    In the controllers, folder create a file called errorHandler.js, inside that file, you are going to create a middleware that handles error in our code.

    
    module.exports = {
      err404: (req,res,next) => {
          const error = new Error('Not Found');
          error.status = 404
          next(error)
        },
      err500 : (error,req,res) => {
        res.status(error.status || 500).send({
          error: {
          status: error.status || 500,
          message: error.message || "Internal Server Error"
          }
        })
      }
    }

    Now that our error handler is set up already, we can go ahead to create the imageController.js file.

    In the file, you can write:

    
    const imageModel = require("../models/imageModel");
    //IMPORT CLOUDINARY CONFIG
    const cloud = require("../config/cloudinaryConfig");
    
    module.exports = {
      createImage: (req, res) => {
        let imageDetails = {
          imageName: req.files[0].originalname,
        };
        //USING MONGODB QUERY METHOD TO FIND IF IMAGE-NAME EXIST IN THE DB
        imageModel.find({ imageName: imageDetails.imageName }, (err, callback) => {
          //CHECKING IF ERROR OCCURRED.
          if (err) {
            res.json({
              err: err,
              message: `There was a problem creating the image because: ${err.message}`,
            });
          } else {
            let attempt = {
              imageName: req.files[0].originalname,
              imageUrl: req.files[0].path,
              imageId: "",
            };
            cloud.uploads(attempt.imageUrl).then((result) => {
              let imageDetails = {
                imageName: req.files[0].originalname,
                imageUrl: result.url,
                imageId: result.id,
                clientId: req.body.clientId,
                clientUsername: req.body.clientUsername,
              };
              // Create image in the database
              imageModel
                .create(imageDetails)
                .then((image) => {
                  res.json({
                    success: true,
                    data: image,
                  });
                })
                .catch((error) => {
                  res.json({
                    success: false,
                    message: `Error creating image in the database: ${error.message}`,
                  });
                });
            });
          }
        });
      },
    }

    So a method has been created for posting an image to the cloudinary server.

    Before uploading the image, it checks the local database if the file already exists by using the MongoDB query find, and if the file doesn’t we upload the file using cloudinary.uploads from the function, we created earlier and post it to the Cloudinary.

    If the file was uploaded successfully, then we create the data on our local database to store the details of the file.

    Setting up Multer

    We can now go back to the config file and create a configuration for multer which we would use to create disk storage where the files would be kept on the server.

    ALSO READ  Getting Started with Database Entity Relationship

    Go to the config folder and create a multerConfig.js file.

    
    const multer = require("multer"),
      path = require("path");
    //multer.diskStorage() creates a storage space for storing files.
    const imageStorage = multer.diskStorage({
      destination: (req, file, cb) => {
        if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
          cb(null, path.join(__dirname, "../files"));
        } else {
          cb({ message: "This file is not an image file" }, false);
        }
      },
      filename: function (req, file, cb) {
        cb(null, file.originalname);
      },
    });
    module.exports = {
      imageUpload: multer({ storage: imageStorage })
    };

    What multer does is just for us to have a store where we can store the files on the server.

    It makes use of the directory specified to store the files and in this case, it was specified to store the images in a folder called files.

    So we can quickly create an empty folder called files in your project directory.

    Now that we have that already, we are going to do a final touch by creating an index route so as to keep our application organized and structured.

    Change your directory to the routes folder and create 3 files called errorRoutes.js, imageRoutes.js and index.js.

    We are going to start writing codes for each file.

    For the first file errorRoutes.js:

    
    const router = require("express").Router(),
      errorHandler = require("../controllers/errorHandler");
    
    router.use(errorHandler.err404, errorHandler.err500);
    
    module.exports = router;

    This file makes use of the errorHandler file create in the controllers folder and that was why it was required at the top of our file.

    We also need to use Express Router in order to handle the routing for this handler and specifically told express to use this controller as a middleware, that was why you saw router.use(...)

    We will go ahead to the next file imageRoutes.js:

    
    const upload = require("../config/multerConfig"),
      imageController = require("../controllers/imageController"),
      router = require("express").Router();
    
    router
      .post("/postImages", upload.imageUpload.any(), imageController.createImage)
    
    module.exports = router;

    In this file, we made use of the multerConfig file to the first check if the file is of the right format and also store it locally before uploading it to the Cloudinary server.


    Finally, we go to our index.js file, this file organizes our routes file and it is used as our entry point in our main app.js file:

    
    
    const router = require("express").Router(),
      errorRoutes = require("./errorRoutes"),
      imageRoutes = require("./imageRoutes");
    
    router
      .get("/server", (req,res)=>{
      res.send('Server seems to be working')
     })
      .use("/images", imageRoutes)
      .use(errorRoutes);
    
    module.exports = router;

    So we are definitely good to go 🙂

    All we need to do now is refactor our app.js file to use the index route file.

    In our app.js file: 

    
    const express = require("express"),
      app = express(),
      mongoose = require("mongoose"),
      router = require("./routes/index");
    
    require("dotenv").config();
    MONGO_URI = process.env.MONGO_URI || "mongodb://localhost:27017/image_files";
    mongoose.Promise = global.Promise;
    mongoose.connect(MONGO_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    // Assign Mongoose connection to the variable db
    let db = mongoose.connection;
    db.on("open", () => {
      console.log("Connected to MongoDB using Mongoose");
    });
    app
      .use(express.urlencoded({ extended: false }))
      .use(express.json())
      //Index route
      .use("/", router)
      .set("port", process.env.PORT || 3000)
      .listen(app.get("port"), () => {
        console.log(`Server running at http://localhost:${app.get("port")}`);
      });

    Testing our Image uploading service

    Now you can go ahead to start the server using node app, after a successful message on the terminal.

    You can open Postman to test the endpoint.

    In your postman, you are going to create a POST request to http://localhost:3000/images/postImages

    In this POST request, you are uploading an image file with the key imageName and the image contents.

    If the image uploaded successfully, you can check the response from the postman.

    LqiHzvnc 1024x557 - How to upload images and videos to Cloudinary using Node.js

    So there you have it, a successful response detailing the imageUrl, imageName and the imageId.

    All these details are stored in MongoDB, you can verify by checking it in MongoDB-Compass(GUI to check your MongoDb instance and collections).

    6ACNJ UE 1024x291 - How to upload images and videos to Cloudinary using Node.js

    You can also check your cloudinary account to verify if the image was uploaded successfully.

    ALSO READ  Laravel Breeze Tutorial: The Definitive Guide (2021)

    Upload Videos to Cloudinary using Node.js


    Now that the image upload controller has been set up successfully, we can now move on to the video upload.

    Create A Video Controller

    Create a new file in the Controllers folder called videoController.js, In the file:

    
    const Video = require("../models/videoModel"),
      cloud = require("../config/cloudConfig");
    module.exports = {
      // Create action for a new video
      create: (req, res, next) => {
        // First check if the file exists in the Database
        let test = {
          name: req.files[0].originalname,
          url: req.files[0].path,
          id: "",
        };
        console.log(req.files[0].originalname);
        Video.find({ name: test.name }, (err, cb) => {
          if (err) {
            res.json({
              error: true,
              message: `There was a problem uploading the video because: ${err.message}`,
            });
          } else {
            let file = {
              name: req.files[0].originalname,
              url: req.files[0].path,
              id: "",
            };
            cloud
              .uploads(file.url)
              .then((result) => {
                Video.create({
                  name: req.files[0].originalname,
                  url: result.url,
                  id: result.id,
                });
              })
              .then((result) => {
                res.json({
                  success: true,
                  data: result,
                });
              })
              .catch((err) => {
                res.json({
                  error: true,
                  message: err.message,
                });
              });
          }
        });
      },
    }

    This is similar to the imageController.js file we created earlier.

    Create A Video Model

    We are going to create a model to synchronise our controller with, let’s get to it.

    In the model’s folder, create a new file called videoModel.js, inside that file write the following code:

    
    const mongoose = require("mongoose"),
      { Schema } = mongoose,
      videoSchema = new Schema(
        {
          name: {
            type: String,
            required: true,
          },
          url: {
            type: String,
          },
          id: {
            type: String,
            unique: true,
          },
        },
        {
          timestamps: true,
        }
      );
    module.exports = mongoose.model("Video", videoSchema);

    Configure Multer for Video

    Now we are all done with the video model, we just need to configure multer again but this time to accept only videos.

    In the config folder, go to multerConfig.js file, inside that file we are going to add the video configuration file:

    
    const videoStorage = multer.diskStorage({
      destination: (req, file, cb) => {
        if (file.mimetype === "video/mp4") {
          cb(null, path.join(__dirname, "../files"));
        } else {
          cb({ message: "This file is not in video format." }, false);
        }
      },
      filename: (req, file, cb) => {
        cb(null, file.originalname);
      },
    });

    Our multerConfig.js file should look exactly as what we have below.

    
    const multer = require("multer"),
      path = require("path");
    //multer.diskStorage() creates a storage space for storing files.
    const imageStorage = multer.diskStorage({
      destination: (req, file, cb) => {
        if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
          cb(null, path.join(__dirname, "../files"));
        } else {
          cb({ message: "This file is not an image file" }, false);
        }
      },
      filename: function (req, file, cb) {
        cb(null, file.originalname);
      },
    });
    const videoStorage = multer.diskStorage({
      destination: (req, file, cb) => {
        if (file.mimetype === "video/mp4") {
          cb(null, path.join(__dirname, "../files"));
        } else {
          cb({ message: "This file is not in video format." }, false);
        }
      },
      filename: (req, file, cb) => {
        cb(null, file.originalname);
      },
    });
    module.exports = {
      imageUpload: multer({ storage: imageStorage }),
      videoUpload: multer({ storage: videoStorage }),
    };

    Create A Video Route

    Finally, we are going to create routes to handle the video upload to Cloudinary, in your routes folder, create a new file called videoRoutes.js and input the following code:

    
    const videoController = require("../controllers/videoController"),
      upload = require("../config/multerConfig"),
      router = require("express").Router();
    
    router
      .post("/postVideo", upload.videoUpload.any(), videoController.create)
    
    module.exports = router;

    Now that we have this ready, we can link it up to routes/index.js, so the complete index.js the file should look like:

    
    const router = require("express").Router(),
      errorRoutes = require("./errorRoutes"),
      videoRoutes = require("./videoRoutes"),
      imageRoutes = require("./imageRoutes");
    router
      .get("/",(req,res)=>{
      res.send("Server seems to be working")
    })
      .use("/images", imageRoutes)
      .use("/videos", videoRoutes)
      .use(errorRoutes);
    
    module.exports = router;

    Testing our Video Upload Service.

    You can test this on the postman, with the following URL http://localhost:3000/videos/postVideo


    You can verify it on MongoDb and Cloudinary.

    Conclusion

    So far, we have been able to create an application that uploads images and videos using Node.js.

    Do you have a way you achieve this task in your day to day activities, let’s hear it in the comment sections below.

    Thanks!!!

    Start Learning Backend Dev. Now

    Stop waiting and start learning! Get my 10 tips on teaching yourself backend development.

    Don't worry. I'll never, ever spam you!

    Sharing is caring :)

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99

    Comments