Storing images in MEAN stack application using "Cloudinary"

Saving images and videos of a web application is always challenging, because, performance of application matters.We have 2 options to deal with this

1. Storing images in database

2. Storing images in cloud

In this article ,i will explain how to store images and videos in "Cloudinary"

Cloudinary

Cloudinary is a cloud-based service that provides an end-to-end image and video management solution. The Node.js SDK provides simple, yet comprehensive image and video manipulation, optimization, and delivery capabilities that you can implement using code that integrates seamlessly with your existing Node.js SDK application.

The following diagrams explains the process of saving User data into database collection.

No alt text provided for this image

It contains 4 steps.

Step-1: Sending user data along with profile image to server by making HTTP POST request

Step-2: Image(or video i.e. a file) of request object can save to cloudinary storage.

Step-3 : Once the file is stored to cloudinary, it returns CDN link of the image

Step-4 : Add the CDN link of profile picture to user data and save it to Database(user collection)



Step-1-Sending user data along with profile image to server by making HTTP POST request

Create register component and register service in Angular application. Then, add registration form to register component.

register.component.html
-----------------------


 <form #ref="ngForm" (ngSubmit)="submit(ref)">

    <!--name-->

   <div class="form-group">

          <label for="n">Name</label>

          <input type="text" id="n" name="name" 
                                     class="form-control" ngModel>

    </div>




      <!--username-->

     <div class="form-group">

     <label for="un">Username</label>

     <input type="text" id="un" name="username" class="form-control" ngModel>

     </div>




            <!--password-->

     <div class="form-group">

      <label for="pw">Password</label>

     <input type="text" id="pw" name="password" class="form-control" ngModel>

     </div>




              <!--email-->

   <div class="form-group">

    <label for="em">Email</label>

    <input type="email" id="em" name="email" class="form-control" ngModel>

   </div>




 <!--date of birth-->

 <div class="form-group">

     <label for="db">Email</label>

     <input type="date" id="db" name="dob" class="form-control" ngModel>

  </div>



  <!--profile image-->

<div>

 <label for="">Choose profile image</label><input type="file" name="photo" id="" ngModel (input)="onChange(f.files[0])"                     
                                                                          #f>

</div>



<!--for selected image preview-->            

<img [src]="imageUrl" />




<!--submit button-->

 <div class="text-center">

        <button type="submit" class="btn btn-success">Register</button>

 </div>

 </form>




register.component.ts
---------------------


import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { RegisterService } from '../register.service';
import { Router } from '@angular/router';


@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {


  //inject register service obj
  constructor(private rs:RegisterService,private router:Router) { }


  ngOnInit(): void {
  }




   file: File;
  
  imageUrl: string | ArrayBuffer ="https://bulma.io/images/placeholders/480x480.png";


   fileName: string = "No file selected";






//this method receives file content ,read and make it ready for preview
       
onChange(file: File) {

    if (file) {
      this.fileName = file.name;
      this.file = file;


      
/*The FileReader object lets web applications asynchronously      read the contents of files (or raw data buffers) stored on the user's computer,
 using File or Blob objects to specify the file or data to read. */

      
      const reader = new FileReader();


//The readAsDataURL method is used to read the contents of the specified Blob or File
      reader.readAsDataURL(file);


/*A handler for the load event. This event is triggered 
  each time the reading operation is successfully completed.
  The FileReader.onload property contains an event handler
   executed when the load event is fired*/


      reader.onload = () => {
        /*  the "result" attribute contains the data as a base64 encoded string.*/

        this.imageUrl = reader.result;
       
      };
    }
  }







//this methid is called at form submission
  submit(formObj:NgForm)
  {
    //formdata obj preperation
    let formData=new FormData();

    //get user object from NgForm object
    let userObj=formObj.value;

      //append image to it
      formData.append("photo",this.file);

     //append user object by converting it into string
      formData.append("userObj",JSON.stringify(userObj));
      
     
     //pass "formData" object to register service to make HTTP POST request 
      this.rs.doRegister(formData).subscribe((result)=>{
        
          if( result["message"]=="user existed")
           {
             alert("user already existed");
             formObj.reset();
           }
         if( result["message"]=="user created")
           {
             alert("user created successfully");
             //redirect to login page
             this.router.navigate(['./login']);
           }
      })


  }
    
}



register.service.ts
-------------------

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';


@Injectable({
  providedIn: 'root'
})
export class RegisterService {


  constructor(private hc:HttpClient) { }


  doRegister(userObj):Observable<any>
  {
    //make http post req and returns Observable
    return  this.hc.post('/user/register',userObj);


  }
}



Step-2: Image(or video i.e. a file) of request object can save to cloudinary storage.

Once the FormData object is reached to server.js, it will execute "userApi.js" by sending request object to it.

server.js
---------

//load express function
const exp=require("express");

//create express obj
const app=exp();


const path=require("path");


//connecting ANgular app with this server
app.use(exp.static(path.join(__dirname,'./dist/AngApp9WithMultipleModules')));




//import MongoClient
const mc=require("mongodb").MongoClient;


//import  user router

const userApiObj=require("./apis/userApi");



//if path contains '/user'
app.use('/user',userApiObj);



//middleware to handle unavailable paths
app.use((req,res,next)=>{
    res.send({message:`path ${req.url} is not available`});
});




//get db url from mongo atlas
var dbUrl = "database url here";


mc.connect(dbUrl,{useNewUrlParser:true,useUnifiedTopology:true},(err,client)=>{
    if(err)
    {
        console.log("Err in db connect ",err);
    }
    else{
        //get db connection object
        let b26DatabaseObject=client.db("database-name");


        //get collection objects
        let userCollectionObj=b26DatabaseObject.collection("usercollection");
       


        console.log("db connected..");



        //assign collection objects to "locals" object of "app"
        app.set("userCollectionObject",userCollectionObject)



        const port=4000;
        app.listen(port,()=>{ console.log(`server listening on port ${port}`)});


    }
});



Now, we need to configure the cloudinary service.For that, register and login into https://cloudinary.com/.

Then it will provide crdentials to use its API and they are "Cloud name","API Key" and "API secret".

Now install and import the following modules at userApi.js

cloudinary

                                               multer-storage-cloudinary

                                               multer


const cloudinary = require("cloudinary").v2;

const { CloudinaryStorage } = require("multer-storage-cloudinary")

const multer = require("multer")


Now configure cloudinary with its credentials.

cloudinary.config({

  cloud_name: "xxxxxxx",

  api_key: "xxxxxx",

  api_secret: "xxxxxxx",

});



Now, after configuring cloudinary, configure storage at cloudinary.

const storage = new CloudinaryStorage({

    cloudinary: cloudinary,

    params:async (req, file) => {

        return {

        folder: 'folder-name-here',       

        public_id: file.fieldname + '-' + Date.now()

    }},

});


Now,configure multer middleware

var upload = multer({ storage: storage });

Then it will use configured storage location at cloudinary to store file data



Step-3 : Once the file is stored to cloudinary, it returns CDN link of the image

Execute multer middleware before request handling middleware by adding it as second argumant like below.

the method "single(string)" will upload single image to storage location.


const exp = require("express");
 const userRouter = exp.Router();


//use body parser middleware
userRouter.use(exp.json());

  

 userRouter.post("/register", upload.single("photo"), (req, res, next) => {

 

   console.log("req body is ",req.body)

   /*multer middleware will execute first before req handling middleware
    save image to cloudinary and get CDN link in req.file.path property*/

   console.log("url is ", req.file.path);
   console.log("user data is ", JSON.parse(req.body.userObj));


    //now parse userObj and assign to req.body

    req.body=JSON.parse(req.body.userObj); 


    //add CDN link of profile image to req.body

 
    req.body.profileImageUrl= req.file.path;

   // write user create logic here..............................

}





Step-4 : Add the CDN link of profile picture to user data and save it to Database(user collection)

The following Code contains user registration logic

const exp = require("express");
const userApiObj = exp.Router();
const bcryptjs = require("bcryptjs")
const jwt = require("jsonwebtoken")
const errorHandler = require("express-async-handler")


userApiObj.post("/register", upload.single('photo'), errorHandler(async (req, res, next) => {
   


    //get user collectionobject
    let userCollectionObject = req.app.get("userCollectionObject")


    let userObj =  JSON.parse(req.body.userObj)


    //console.log(userObj)



    //console.log("req body is ",req.body)


 
    //check for user in db
    let user = await userCollectionObject.findOne({ username: userObj.username })


    //if user is existed
    if (user !== null) {
        res.send({ message: "user existed" })
    }
    else {


        //hash the password
        let hashedPw = await bcryptjs.hash(userObj.password, 6)
        //replace plain text pw with hashed pw
        userObj.password = hashedPw;


        //add userImagelink
        userObj.userImgLink = req.file.path;
        //create user
        let success = await userCollectionObject.insertOne(userObj)


        res.send({ message: "user created" })
    }



}))



Now the user collection of database contains user object will all user data along with CDN link of his profile image.




























Rajesh T

Java Full stack & JavaScript Full Stack(MEAN ,MERN &Next.js) Developer & Instructor

4 年

Thank you Sam Brace

回复
Sam Brace

Senior Program Lead @ Shopify | Merchant and Partner Education

4 年

Thanks for sharing these details! ??

回复

要查看或添加评论,请登录

Rajesh T的更多文章

  • What is an API ?

    What is an API ?

    An API is a set of rules and protocols that allow different software applications to communicate with each other. Types…

    1 条评论
  • Redux vs Zustand for state management in React app

    Redux vs Zustand for state management in React app

    "A JS library for predictable and maintainable global state management" - Redux "A small, fast, and scalable bearbones…

    1 条评论
  • Simple state management in MEAN Application

    Simple state management in MEAN Application

    State management in Web apps is always challenging. Here, I have taken a simple e-learning app to demonstrate, state…

    1 条评论
  • Shallow copy vs Deep copy

    Shallow copy vs Deep copy

    Copy to an object can be created in many ways in JavaScript. Let us first understand difference between primitives and…

  • Units in CSS

    Units in CSS

    Absolute length units The absolute length units are fixed and a length expressed in any of these will appear as exactly…

  • Promises in JavaScript

    Promises in JavaScript

    The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting…

  • Callbacks in JavaScript

    Callbacks in JavaScript

    Most of us feel confusion while learning about asynchronous behavior of JavaScript. In this article i tried to explain…

  • Error handling in Express Application

    Error handling in Express Application

    Error Handling refers to how Express catches and processes errors that occur both synchronously and asynchronously…

    1 条评论
  • Connecting Angular application with Nodejs backend

    Connecting Angular application with Nodejs backend

    In this article, i will explain ,how to connect Angular Application with Nodejs backend. When we create a new angular…

  • Token based Authentication in ExpressJS Application

    Token based Authentication in ExpressJS Application

    HTTP is a stateless protocol. That means ,it cannot maintain state of previous requests.

社区洞察

其他会员也浏览了