The Ultimate Node JS Course 2026: Express, MongoDB, REST APIs, Socket & More | Code Bless You | Skillshare

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

The Ultimate Node JS Course 2026: Express, MongoDB, REST APIs, Socket & More

teacher avatar Code Bless You, Make Coding Easy To Learn

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Class Introduction

      2:57

    • 2.

      Section 01 - What is NodeJS

      5:51

    • 3.

      History of NodeJS

      2:40

    • 4.

      How NodeJS Works

      5:48

    • 5.

      Installing Node JS in System

      3:17

    • 6.

      Writing first node code

      5:26

    • 7.

      Make VS Code Cool [OPTIONAL]

      1:59

    • 8.

      Section 02 - What are modules

      3:52

    • 9.

      Creating own Module

      6:47

    • 10.

      Accessing module in other module

      5:10

    • 11.

      Exercise for own Module

      3:04

    • 12.

      Using Path Module

      7:13

    • 13.

      Getting Operating system details

      3:08

    • 14.

      File System Module

      4:13

    • 15.

      Creating Server using HTTP module

      5:18

    • 16.

      How to handle different routes

      3:41

    • 17.

      Section 03 - NPM Introduction

      2:27

    • 18.

      Creating Package

      4:20

    • 19.

      Installing package in project

      4:07

    • 20.

      Uninstalling packages

      1:03

    • 21.

      Install package as Developer Dependency

      1:46

    • 22.

      Outdated packages and update them

      5:56

    • 23.

      Remove unused packages from project

      1:48

    • 24.

      Section 04 - API vs REST API

      7:41

    • 25.

      Planning API List for Project 01

      1:49

    • 26.

      Setup a new application

      1:08

    • 27.

      Build server using Express

      6:39

    • 28.

      Exercise for Creating Express Server

      2:36

    • 29.

      Creating API for Getting all todos list

      3:34

    • 30.

      Setup nodemon auto restart

      1:55

    • 31.

      Environment Variables

      3:42

    • 32.

      Route Parameters & Query Parameters

      5:43

    • 33.

      Get Single Todo by ID

      4:47

    • 34.

      POST API for Adding new todo

      11:06

    • 35.

      Validating user Data

      3:20

    • 36.

      Passing status code

      3:10

    • 37.

      res.send & res.json

      3:12

    • 38.

      Update single Todo with PUT Request

      5:29

    • 39.

      Exercise Delete Specific Todo

      3:48

    • 40.

      Section 05 - Introduction of Middleware

      4:09

    • 41.

      Creating Custom Middleware

      3:17

    • 42.

      Built in Middleware

      4:51

    • 43.

      Sharing Static Files from Server

      4:28

    • 44.

      Useful Third party middleware

      4:58

    • 45.

      How to Code according Environment

      4:02

    • 46.

      env file & dotenv package

      3:47

    • 47.

      Different Settings for different ENV

      3:43

    • 48.

      Template Engines in Node Application

      5:59

    • 49.

      Cleaning up the Code Application Structure

      5:34

    • 50.

      Section 06 - Asynchronous vs Synchronous

      9:45

    • 51.

      Callbacks in JavaScript

      6:32

    • 52.

      Solving Problem using Callback

      7:31

    • 53.

      Callback Hell

      3:39

    • 54.

      Promise in JavaScript

      5:51

    • 55.

      Replacing Callbacks with Promises

      7:51

    • 56.

      Async:await in JavaScript

      6:51

    • 57.

      Section 07 MongoDB Basics

      1:16

    • 58.

      Introduction of Database

      4:34

    • 59.

      Install MongoDB in Windows

      4:19

    • 60.

      Connect MongoDB with Node App

      5:41

    • 61.

      Importance of Schema

      3:15

    • 62.

      Defining Schema for Document

      4:05

    • 63.

      Creating Models

      3:48

    • 64.

      Saving a new Data

      4:46

    • 65.

      Query the Data

      7:48

    • 66.

      Comparison Operators in MongoDB

      6:17

    • 67.

      Logical Operators in MongoDB

      6:56

    • 68.

      Regular Expression in MongoDB

      5:23

    • 69.

      Count and estimate Document Count

      2:46

    • 70.

      Pagination & Infinite Query

      6:37

    • 71.

      Update the Data

      9:20

    • 72.

      Update Operators in MongoDB

      1:42

    • 73.

      Delete the Data

      3:01

    • 74.

      Exercise 01 - Configure MongoDB

      7:16

    • 75.

      Exercise 02 - For Storing Data

      5:59

    • 76.

      Exercise 03 - Fetching Data

      5:52

    • 77.

      Exercise 04 - Updating & Removing Tasks

      8:21

    • 78.

      Section 08 - Built in Validators

      6:42

    • 79.

      Custom Validators

      4:28

    • 80.

      Async Validators

      1:59

    • 81.

      Useful SchemaTypes Options

      0:55

    • 82.

      Relationship between models

      5:05

    • 83.

      Hybrid approach for Relationship

      2:23

    • 84.

      Applying Reference Approach

      4:41

    • 85.

      How to extract data from Reference [Populate]

      2:47

    • 86.

      Applying Embed Approach

      4:25

    • 87.

      Applying Hybrid Approach

      3:11

    • 88.

      Indexes in MongoDB

      10:54

    • 89.

      How indexes works in MongoDB

      9:47

    • 90.

      Section 09 - Project 02 and Planning

      1:51

    • 91.

      Creating a new server

      2:39

    • 92.

      Connecting to Database

      2:15

    • 93.

      Exercise - Creating User Model

      4:10

    • 94.

      Creating the new user

      12:26

    • 95.

      Hashing the password for security

      5:16

    • 96.

      User input validation using Joi

      8:45

    • 97.

      How authentication works

      3:30

    • 98.

      Generate the JWT token for user

      5:45

    • 99.

      Setting Expiry of Token

      2:19

    • 100.

      Secure the Security key in Enviroment

      2:13

    • 101.

      Exercise Create Login route

      8:11

    • 102.

      How to Authenticate User? Logged in or Not?

      12:56

    • 103.

      OAuth in Details

      5:44

    • 104.

      OAuth in Node Application - Signin with google

      15:03

    • 105.

      OAuth with JWT

      16:36

    • 106.

      Sign in with Facebook using OAuth

      10:37

    • 107.

      Simplifying the Code

      3:00

    • 108.

      Problem with Single Token [UPDATE]

      2:16

    • 109.

      Access Token & Refresh Token Logic [UPDATE]

      7:17

    • 110.

      Implement Access Token & Refresh Token [UPDATE]

      9:24

    • 111.

      Refresh Route for New Access Token [UPDATE]

      10:37

    • 112.

      OAuth with two tokens [UPDATE]

      2:21

    • 113.

      Route for Logout a User [UPDATE]

      3:55

    • 114.

      Section 10 - Creating the Category Model

      3:58

    • 115.

      Create a new Category API with Image upload

      11:27

    • 116.

      Set file name & filter in multer

      11:55

    • 117.

      Getting all categories API

      1:39

    • 118.

      Sharing Static Images from the Server

      2:06

    • 119.

      Exercise - Defining Products Model

      6:56

    • 120.

      Role Based Authorization

      8:59

    • 121.

      Custom Role Based Authorization

      5:40

    • 122.

      Handling Multiple Images of Products

      3:30

    • 123.

      Create new Products

      7:16

    • 124.

      Getting all Products Data

      11:37

    • 125.

      Pagination or Infinite Query

      5:58

    • 126.

      Sending Products By Category

      3:17

    • 127.

      Sending Product By Search

      2:25

    • 128.

      Exercise - Getting Single Product Data

      5:50

    • 129.

      Exercise. - Deleting the Product

      10:52

    • 130.

      Searching Product by Title [OPTIONAL]

      4:05

    • 131.

      Section 11 - Why we handle errors?

      2:44

    • 132.

      Handling Rejected Promises

      3:25

    • 133.

      Create Error Middleware

      3:26

    • 134.

      Remove try catch blocks

      1:44

    • 135.

      Log errors in file

      11:46

    • 136.

      Log errors in mongoDB

      2:24

    • 137.

      Uncaught Exceptions

      7:16

    • 138.

      Unhandled Promises Rejections

      3:23

    • 139.

      Recap of Error Handling & Logging

      1:50

    • 140.

      Section 12 - Creating Cart Model

      6:50

    • 141.

      Defining API list for Cart

      1:22

    • 142.

      Adding Products to Cart

      20:38

    • 143.

      Getting the User Cart

      2:23

    • 144.

      Increase the Product Quantity

      9:22

    • 145.

      Decrease the Product Quantity

      3:58

    • 146.

      Removing Single Product from Cart

      5:34

    • 147.

      Creating Orders Model

      4:27

    • 148.

      Workflow of Payments

      3:53

    • 149.

      Implementing Razorpay Payment Gateway

      49:43

    • 150.

      International Payment using Paypal

      49:15

    • 151.

      Getting history of orders

      2:21

    • 152.

      Updating status by admin

      5:17

    • 153.

      Cleaning up code for index file

      3:27

    • 154.

      Section 13 - Introduction of Project 03

      1:05

    • 155.

      Setting up Project 03

      5:14

    • 156.

      Create User Model

      4:23

    • 157.

      Registering a New User

      10:35

    • 158.

      Exercise - User Login API

      0:28

    • 159.

      Solution - User Login API

      4:53

    • 160.

      Implement Access Token & Refresh Token [UPDATE]

      5:16

    • 161.

      Refresh & Logout Route [UPDATE]

      9:00

    • 162.

      Current Logged in User Details

      7:27

    • 163.

      Resetting User Password

      13:11

    • 164.

      Ways of sending email in Node JS

      2:17

    • 165.

      Setup Amazon SES for Sending Email

      21:09

    • 166.

      Sending Emails for FREE

      10:13

    • 167.

      Follower and Following Logic

      2:18

    • 168.

      Follow the User

      9:08

    • 169.

      Accept the follow request

      7:45

    • 170.

      Exercise - Getting the list of Followers and Following

      6:24

    • 171.

      Exercise - Unfollow the User

      3:34

    • 172.

      Section 14 - Introduction

      0:26

    • 173.

      Create Post Model

      3:43

    • 174.

      Create a new Post

      15:43

    • 175.

      Getting current user posts

      4:16

    • 176.

      Getting Home Feed

      9:31

    • 177.

      Deleting the post

      6:51

    • 178.

      Like and Unlike the Post

      4:56

    • 179.

      Implementing Comments Feature

      6:15

    • 180.

      Adding Reply to Comments

      5:21

    • 181.

      Exercise - Removing Specific Comment

      4:37

    • 182.

      Error Handling

      3:06

    • 183.

      Section 15 Introduction

      1:10

    • 184.

      Creating Chat - Message Model

      6:23

    • 185.

      Getting Chats For User

      6:32

    • 186.

      Getting Messages of Specific Chat

      3:44

    • 187.

      API for Sending Messages

      10:02

    • 188.

      What are Web Sockets

      5:16

    • 189.

      Connection of Socket

      8:20

    • 190.

      Socket Emit and on methods

      8:07

    • 191.

      Getting messages for both users

      2:02

    • 192.

      Logic of Joining Chat Room

      3:00

    • 193.

      Implementing Joining a Chat Room

      4:35

    • 194.

      Exercise - Typing Indicator

      8:48

    • 195.

      Applying real send message code

      5:33

    • 196.

      Authenticate user in Socket

      10:52

    • 197.

      Marking users as Online and offline

      3:44

    • 198.

      Multiple sockets for Single user

      5:50

    • 199.

      Update messages deliverd

      17:15

    • 200.

      Updating message status to seen

      8:53

    • 201.

      Adding Group Fields in Schema

      2:42

    • 202.

      Create a new Group API

      3:41

    • 203.

      Adding Group Chat Logic in Socket Events

      14:22

    • 204.

      Section 16 - Deployment Options

      2:32

    • 205.

      Simplifying the Code

      8:18

    • 206.

      Preparing Node app for Production

      2:58

    • 207.

      Overview of Deployment Process

      0:39

    • 208.

      Uploading Node application on Github

      5:52

    • 209.

      Deploying Node App on Render

      3:37

    • 210.

      Adding MongoDB Cloud

      6:51

    • 211.

      What is MVC Architecture? [BONUS]

      7:00

    • 212.

      Apply MVC Architecture [BONUS]

      20:56

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

69

Students

--

Projects

About This Class

Welcome to The Ultimate Node.js Masterclass 2025 — a complete, 20-hour journey into modern backend development. In this class, you’ll go beyond theory and actually build real-world projects using Node.js, Express, MongoDB, Socket.IO, and more.

Whether you’re aiming to become a full-stack developer, land your first backend role, or simply understand how Node.js works under the hood, this class gives you everything you need in one place.

What You Will Learn:

  • Understand the core concepts of Node.js including modules and built-in libraries.

  • What is Node JS? How node works under the hood
  • Build and structure RESTful APIs using Express.

  • Work with MongoDB and Mongoose to store, query, and manage data.

  • Implement user authentication with JWT tokens.

  • How to Add OAuth sign-in with Google and Facebook.

  • Create password reset flows using Amazon SES and SMTP.

  • How to Integrate payment gateways like PayPal and Razorpay.

  • Build real-time features (1-to-1 chat and group chat) using Socket.IO.

  • Deploy Node.js applications

  • Much more

Why You Should Take This Class:

Backend development is at the heart of every modern web and mobile application. By mastering Node.js, you unlock the ability to:

  • Build scalable, production-ready APIs that power real applications.

  • Add real-world features like authentication, payments, and chat to your projects.

  • Apply your skills to freelancing, startup projects, or professional developer roles.

  • Stay up-to-date with 2025 industry standards in backend development.

I’ve designed this class to take you from beginner to confident backend developer step by step, with a focus on hands-on learning and real-world use cases.

Who This Class is For

This class is for:

  • Beginners who want to start backend development with Node.js.

  • Frontend developers who want to become full-stack engineers.

  • Students, entrepreneurs, and aspiring developers who want to build complete, real-world apps.

No prior backend knowledge is required, but you should already be familiar with basic JavaScript (variables, functions, arrays, objects).

Materials/Resources

To take this class, you will need:

You’ll also get access to starter code, project templates, and example files to help you follow along.

 

Meet Your Teacher

Teacher Profile Image

Code Bless You

Make Coding Easy To Learn

Teacher

Hi! I'm a passionate software engineer from Code Bless You and I love to teach about coding and general skills in less time. I've taught many people how to become professional software engineers.

My goal is to make coding fun for everyone. That's why my courses are simple, animated, and with practical implementation.

Learn by doing

Step-by-step tutorials and project-based learning.

Get support

One-on-one support from experts that truly want to help you.

don’t stress. have fun.

I can't wait to see you in class!

- Code Bless You

See full profile

Level: Beginner

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Class Introduction: Welcome to the ultimate noJS course. In this course, you will learn all about nodejs from basic to advance in simple and easy to understand language. At the end of this course, you will start building fast, scalable and secure pend applications without getting confused. Let me tell you some major features covered in this course. So you will learn database connection. Pagination and infinance scrolling, user authentication, as well as sign in with Google and sign in with Facebook features, sending emails from our backend, uploading multiple images, handling and logging errors, apply full payment integration using paper, and also real time chatting features using socket sending one to one messages, showing typing indicators, handling message status, is it sent delivered or seen, and also group chat features. Now for learning these advanced concepts, we need a strong base. So first, we will start with learning nodejs basics like core concepts of node, built in modules, Express, which is the most popular and most used nod Js framework, some JavaScript repressor concepts like callbacks, promises, missing await. Also, we will see Mongo DB and mangoes, and if you understand basic concepts clearly, then you can implement any advanced topics of node jazz very easily. Also, I want to clear one thing. In this course, we are not going to create front end because it is not the scope of this course, but we will taste some features with front end so you will get clear understanding of full workflow of these features. I will give you front end ready code for tasting, so you have to just run that file and you can taste some features. It is really fun. So if you know a little bit about node jazz, or you are confused in concepts, if you don't know anything about no Jazz, then this course is for you. During this course, we will build three applications back end. First, to do application for learning basic concepts, and then two major projects ecommerce application and social media application back end, for learning advanced node Jazz concepts. Now you might ask who am I? I am a software engineer and also teach programming in easy to explain language using my YouTube channel, God bless you, and with my online courses. Overall, in this course, you will get 200 plus SD video lessons, real world implementation, bunch of exercise, so you can learn no Js with practical implementation, some tips and tricks, and much much more. After completing this course, you will write No JS code with confidence and using best techniques, so quickly enroll and become no Js o to No Jazz hero. CU in this course. 2. Section 01 - What is NodeJS: NodeJS is the most popular for developers, but it is not a programming language or it is not a framework. Then what is really nod Js? Let's see that. Nojs is simply a runtime environment for running JavaScript code outside of the browser. What do I mean by that? So as we know, we use JavaScript code for changing the data on the web page or implement some logic, but we can't run Ja Script outside of the browser. Have to link our JavaScript file with our SDML file, and then we can run it on our browser. But with nodejs, we can run JavaScript code outside of the browser. Nodejs provides a runtime environment for running JavaScript code. Developers mostly use Nojz to build backend services called API or we can says application programming interface. Now you might ask what is an API? Basically, it is a way for two programs communicate with each other. Me explain you that with example. So here is a restaurant. We are sitting on the table n, and we want to order some food. In this case, what we will do? We cannot directly go to the kitchen and order our food to chef. Instead of that, we will call a waiter. Waiter, will take our order and then give it to the kitchen. After that, kitchen start making process of our order and give food to the waiter, and then Waiter will deliver the food to our table. So here, Water is like a messenger who takes our request and pass that request to our destination. And then Waiter will get reply message from that destination and bring back to us. So in real world, this table n on which we are sitting is our client application or front end. We want to get some data about food which is available on the back end. We will call Waiter, which is an API and send requests to it. Now, API will transfer that request to server or database, which is our kitchen, and that server or database will share the response, which is the data we want. And API deliver the response data to our client. Now you understand what is an API. API is a way for two programs communicate with each other. With NodeJS, we can build real world APIs. Also, we can build superfast real time applications with node JS. These services give power to our client applications like web applications and mobile applications very useful. Do you know, Netflix, Paper, Uber, Lin DIN, and many more famous companies use No Jazz? Yes, because Noe Jaz makes their services super fast and efficient. Also, P done a great research on Noe Jaz. I will tell you that in just a minute. So to summarize, Node Jazz is a runtime environment, and it is ideal choice for building highly scalable data related and real time applications. Now you might ask, there are many frameworks and languages like Java and asp.net, which can also build wegen services. What is special about Node Jazz? Why should we learn node jazz? Why it is so popular? First of all, with no jazz, we can build super fast and highly scalable backend services with low cost. Also, people did a great experiment with no jazz. In that experiment, people create its application back end using no jazz and also build the same application with Java plus spring. And do you know the result of that experiment? It is really shocking. They found node application built twice as fast than Java plus spring application and with fewer people. In Java plus spring, they have five developers, then in node, they only need two developers, and still those two developers build application faster in nodejs. Also, node application takes 40% fewer files. Also, in Java, they have 5,000 lines of code, but in nodejs, they have only 1,500 lines of code, which is three x less. So node application is super faster, 35% faster response time than Java application, and node application can serve almost two X requests per second than Java application. This result shock everyone and people immediately migrated many services from Java to node Jz. Is really cool, right? Second, with node jazz, we get cleaner and more consistent code base because with less code, we can do many complex things. Also, it is great for prototyping, which means node Jazz is fast and easy to use when building the first version of an application. First version is called as prototype. Also, as we know, in node jazz, we will use JavaScript. So if you are friend end developer, you can easily learn node Jazz without learning a new programming language. And if you learn both frontend and backend, then you can switch your job role as full stack developer and improve your career and get more salary. And one more benefit of Nojs is Nojz has large ecosystem of open source libraries, which means there are predefined code for doing particular things. So we can use someone else's code and implement their features in our application. So overall, learning nodejs in 2025 or in future will definitely benefit you and your programming career. 3. History of NodeJS: In the previous lesson, we see No Jazz is a runtime environment for running JavaScript code outside of the browser. But let's see how Noe Jazz invented with interesting story. Before 2009, JavaScript was like a superhero trapped inside a browser like Chrome, Firefox, and many more browsers. In all these browsers, there are JavaScript engine. When we run our JavaScript code inside the browser, browser pass that code to JavaScript engine. JavaScript engine process that code and convert it into machine code, which our computer can understand. For example, Microsoft Taj use Chakra Engine, Firefox, use Spider Monkey engine, and Google Chrome, use Fiat Engine, which is the most powerful JavaScript engine among all browsers. Because of these different JavaScript engines, sometimes JavaScript code works differently in different browsers. When we use JavaScript inside browsers only, then there are many limitations. We can't build servers or do Bend task like handling database, user authentication, or APIs. Now, at the time a developer, Yandll comes into the picture. He thinks, what if we take Vat engine and let JavaScript run on servers instead of just browsers. He takes the Vet engine, which is the fastest Js engine and record that engine in CplusPlus code. Can run Jascip code in our machine and call that software nodejs and that's SOO nodejs invented. Nod Js is a runtime environment for running JavaScript code because it has V JA Script engine. This environment is little different than we have in our browser. Like in the browser Ja script, we have document object for dealing with SDML document. Also we have Window object. These objects we don't get into node Jazz and also we don't want to access document and Window objects because in node jazz, we are creating back end services, and document and Window objects are for front end task. So why we need document and window in the back end? With the node js, we can do many more things like we can access the file system for read and write files. We can connect with database and store data in database, and also we can build fast APIs and much more things. Now, one question you might ask how nodejs is super fast, how no Jz works, and we will see that in the next lesson. 4. How NodeJS Works: So we have seen that nodejs is used for super fast and highly scalable backend applications. But how nod Js is super fast. So the reason no Js is super fast is because of its non blocking or we can say asynchronous nature of node js. Now you might ask what is asynchronous? Let me explain you with simple example. Imagine here is a restaurant. We have one kitchen here and we have multiple tables. Now first customer wants to give order. So here, our waiter, go to the table one, get order. Let's say one pizza. And then our waiter give that order to the chef in the kitchen. Now while sef making pizza, our waiter will look at other tables. Let's say Table two wants to give another order, then waiter take that order and also give it in the kitchen. Our single waiter can handle many tables. He don't need to wait for chef to complete one order, and then he can serve another order. He don't need to do that. This is called as non blocking or asynchronous way, and this is how node application works. This single weiter is working as single thread of node JS, whose task is to handle request. So this single thread can use to handle multiple requests without blocking. Now at the other side of this asynchronous way, we have also synchronous or blocking way. Let's understand that also with the same example. So here, customer Vn wants to give order. Our waiter take order from table one and give it to the kitchen and our self start preparing for that order like pizza. Now, as we know, pizza can take time to prepare. At that time, instead of handling other tables, our waiter wait there in the kitchen for complete that order. Suppose it takes 10 minutes, so our waiter will wait there for 10 minutes in the kitchen. After that, deliver that pizza to table one. Now, at that time, customers on other tables have to sit because our waiter is blocked for 10 minutes. This is called as blocking or synchronous way. Most of the older back end frameworks like w.net or Rails works in synchronous or blocking way. So when someone send requests on the server, server allocate one thread to handle that request. Our example, it is weiter. Now imagine we have request for getting the list of users. This task needs database operation which can take time. Now, if at that time we get another request, then to handle that new request, we need to also give them a new thread or weiter. Now imagine on our server, there are 1,000 requests. Should we create thread for all those requests? If yes, then we have to increase the number of server hardwares, which is really costly and slow. That's why applications which are built on asp.net or rails need more number of servers and more maintenance. Now, at that time, node comes in the picture, and as we have seen, node use asynchronous or non blocking way. Of course, we can make asp.net or Rails application works like non blocking or asynchronous application. But for that, we need to do extra work. On the other side, node applications are works by default asynchronous or non blocking way. So it is really fast and easy to manage. When we get multiple request on node server, node has single thread. That single thread can handle one request. Now, if that task takes time, find something from database, then our single thread add that task in the list called event Q and move to another request and start handling that request. This event Que will notify node when they get data from the database, and then our node will send that data to the request. So in this way, our single thread can serve multiple users, and that's why nodejs is a great option for data intensive or network related applications. Can serve more clients without adding more servers, and that's why node applications are also highly scalable. Now the question is, should we use node Jazz for all types of applications? And the answer is no. We should not use node for CPU intensive applications. Now, what is the CiPi intensive? CPU intensive means applications which have tasks related to CPU like video editing or photo editing applications. In these types of application, we have a lot of calculation that can use CPU few options, which does the file system or network. And as we know, node is a single threaded application when it performs CPI related operations when other clients has to wait to complete that task. Here, node will lose its advantage of being asynchronous, and that's why we should not use node for SIPEintensive application. Can use node for input output, network related, or real time data related applications. Just remember we should not use node for CiPi intensive applications. Otherwise, node can use for mostly all kinds of application. So we understand how nod Jazz is faster than other back end frameworks. Don't worry about the theories. As you build projects in node Jaz, you will understand all the very easily. So let's start learning node Jaz practically. 5. Installing Node JS in System: Let's see how to install NodeJS in our system. First of all, we will check if Nojs is already in our system or not. So open up Command Prompt in Windows, and if you are using Mac or Linux, then open up your terminal and write node, dash dash version, and hit Enter. See here I get this kind of error message, node is not recognized as an internal or external command. This means node is not installed in my system. If you get here nodejs version, which means node is already installed in your system, but I highly recommend you to install the latest table version of node JS. So head over to browser and opennjs.org. On this website, we get a download Nodjs LTS version, which means latest table version which node officially recommend to use. At the time I'm recording this course, latestable version is 22.14 0.0. But in the future, there might be updated version available. So simply click on this version, and download will start. One question you might ask, is this course relevant for the future node versions? And the answer is yes. This course will stay relevant for any node JS version because in this course, we are going to strongly focus on the fundamentals of node JS, and you can use that fundamentals in any node JS version. So you don't need to worry about no JS updates. If any major updates occur, then I will update this course according to that. Now our setup is ready to install. So let's open it up. Let me put here Click on next, accept the terms and condition and click on next. From here, you change the installation path, but in my suggestion, leave it as it is. Again, click on next and next and install. And it's done. Now, let's check Nojs is installed successfully or not. So back to command prompt or terminal and write nodes version, and hit Enter. See, now I get here nod Gs version 22.14 0.0. So we successfully install node in our system. Another thing we need in this course is code editor. Personal favorite code editor is Visual Studio code or VS code, which is one of the best code editor. Of course, you can use any other code editors, but not many editors has that power which VS code has. And also, in this course, I will share my tips and tricks for VS code. So if you don't have VS code, then you can go to code.visualstudio.com, download VS code and install it. It is really simple. Now in the next lesson, we will write our first node JS code. 6. Writing first node code: Let's write our first node JS code. Open a folder in which you want to create a project. Here, I open Project folder, and in this folder, I create a new folder, let's say, first project and simply open this project in VS code. Good. This VS code looks a little bit smaller for this course. So let me zoom it. Usually, I don't zoom in this much, but with this Zoom, you can see what I'm doing clearly. Perfect. Now let's create a new file here. Let's say index dot js. You can use any name. It's totally up to you. Now inside this file, we can write our normal JavaScript code, which we are used to write. So let's simply create a variable called greeting equals to good morning. And after that, we simply consult that log. Hello comma and simply adhere greeting variable. Save this file. Now you might ask, how can we run this code without our browser? Because previously, we are running JavaScript using browser. So to run this code using no chairs, we need terminal. And use our system terminal and open our project folder in that terminal, or we can use VS code terminal. I always use VSCode terminal because it is easy to open, go to the terminal menu and select new terminal, or you can press Control plus Pecti. It will open here terminal. Now to run this index dot js file, we simply write node, space, and our file name, which is index dot js. Your file name is apt Gs, then you have to write here nodspace app dot js and hit Enter. See, here we get our Console line. So congratulations. You write your first nodejs code. Now to hide this terminal, we can again press Control plus Bectig. Now here we can also add function and call that function, same as we are doing in regular JavaScript. So after console dot log in the new line, we can create a function print message. And in the Cully brackets, we simply console dot log. Have a nice day. And after this function, we simply call this print message function, so we can get this console message, save this file, and to again run this file, what do we write in the terminal? Write, we write node space index dot js. See here we get this both Console Loui. So we can use here set timeout function, set interval function, et cetera. We can add almost all JavaScript code in the node application. Now you might ask which type of JavaScript code we can't add here in the node JS project. So in NodeJS project, we can add all types of JavaScript code, except writing doom manipulation code like document dot Get element or window dot location, et cetera, because as we know, whatever code we write in node application, will run on server and on server, how can we access document and Window objects? Let me show you practically what will happen if we use document in this index dot JS file. I comment out all this code using Control plus slash or Command plus slash and simply right here, console dot log. Print here document object. Save this file, and in the terminal, we again run node index dot js, or we can simply press a perro. It will bring previous command for us. See, here we get error which says document is not defined, and it is A showing us the line. So we can't use here doom manipulation code. Another thing is we also can't use here browser specific events like Alert. So at the place of this console we add Alert, say hello. Save this file, and let's run again this file. See here we get Alert is not defined because again, these are browser related events. Server can't show Alert in the browser. It is the front end who can show Alert. So to sum up in index Js file or any other files in node project, we write JavaScript code for server we can use various modules, handle SDDPRquest, access our system files, connect to database, build real time applications, and many more things which we will learn step by step in this course. Don't worry, you will master node after this course. Just you have to code along with me and try to write code after you understand it properly. Not just copy and paste. You have to understand why we write that specific code and then implement it. It is really simple. 7. Make VS Code Cool [OPTIONAL]: In the previous lesson, if you wonder how my code gets reformatted when I save the file. For that, I'm using one of the best and most popular VS code extension called pretty. Install this extension. Now we have to do little settings for installation of Pretty E. So in the installation section, scroll down to the default formatter section. And here, copy these two lines of code without Cully brackets. Now, open up settings from the bottom gear icon, go to settings, and at the top right corner, from here, open settings, touches and file, and at the last line, add comma and then in the new line, past those lines. See this file. Now back to settings and search format on save and make sure it is checked and done. Also, many students ask me which theme and fonts I use for my VS code. So currently, I am using my favorite theme, which is Au Mirage Warder. You can download that from the extension panel. This theme is not very bright or not very dark, so it's good for our eyes and it looks good. The name of the font which I'm using is Monisa. Which is the paid font, you can download this font whichever way you want. I can't say anything further. Install them in your system. And then from the VS code setting, search here font family and add your font name at the very beginning, and that's it. You can use any theme and fonts you like. It's totally up to you. And if you have a great combo, then you can add your VS code screenshots in the Q&A section. I love to see that, and that's it. We are ready to go. So let's dive into this node JS code. 8. Section 02 - What are modules: Welcome to the second section of the ultimate node JS course. In this section, we will learn everything we need to know about modules like what are modules? How can we create our own modules? Also, we have some built in modules like path, operating system, file system, DTP module for creating server, and much much more. Let's start with what are modules. But before that, let me give you one situation. In the previous section, we created this index dot JS file. Now imagine this is the Began project of Netflix, which is the really big project. This project has many features like database connection, user authentication, payment gateway, also many other APIs. Now imagine we add this all feature code in single index dot G file. How will you manage this? Or if someone told you to add another feature in the same project, then imagine how confusing and difficult it will be. What is the solution here? Think about it. Here, we can separately create these features in different files and then simply input them in the main index NodeJS file. These different small files are called as modules in node JS. If I had issue in database connection, I can go to the database connection module and resolve or improve that code independently. To sum up, module is a piece of code that perform a specific task. Example, imagine you are building a car. A car has many parts like engine, wheels, sheets, et cetera. Each part is built separately, and also it can be replaced or repaired without affecting the entire car. Now in node JS, modules work similarly. Each module represents a different part of our application, and these modules can work together to form a complete application. And that's why modules are very important part of node JS. Now we can divide modules in three types. First one is local modules. These are the modules which we will create for our own application like DB module for database connection, payment module for handling payments, et cetera. Second one is core modules. These are the built in modules which we get with node JS. They are already available in all node applications. For example, FS for file system, STTP for creating STTP server or making STTPRquest. OS for operating system related functionality, and many more. Don't worry, I will explain you our core modules in the upcoming lessons of this section. Now the third one is third party modules. These are the modules which are created and published by other developers. If we want to use them, then we have to manually install those modules in our project. For example, express dot js is third party module, which helps us to build API fast. Another module is Mongoose for Mongo Div et cetera. These are third party modules built by someone else, and we can also use them in our project. Don't worry about all these things, we will go step by step and learn each of them. So to quickly summarize, module is a piece of code that perform a specific task. We can store them in separate files, and then we can use them in any other files. Now in the next lesson, we will create our own module. 9. Creating own Module: Let's build our own custom module. So here in our application, we create a new file called math operations dot js. In this module, we will add some basic math operation and then reuse it in our main index dot js file. So first of all, let's create a new function called AD and pass here two parameters called A and B. And inside this function, we simply written addition of these two parameters, A plus B. You might ask, how can we use this function inside our index dot js file? Because we all know when we define function inside one file, we can only use it in that file, not outside of the file. So to use this ad function in other file, we have to export this function from this math operations module, and then we can import it in index dot js file. But before that, let me show you something. So in nodejs all files have one object called in that module object, we have many properties which gives information about that particular module. Let me show you that practically. After this function, we simply write console dot log and print here module object. Now we have to run this Mth operations module. So open terminal and write node, math, and press tab. It will autocomplete the file name. See, here we get this module object with a bunch of properties. First one is ID, which is the unique ID for module. Next, we have path, which is the full path of our project. After that, we have export and it is set to empty object. You guess correctly, if we want to export add function, then we have to add their function in this export object. After that, we have current file name with full path and bunch of other properties. Now, how can we add add function inside this export object? It is really simple. So here we write module dot exports dot add, which is the property name equals to add function. Make sure we don't call here add function. We just add here function name. I know you think this is a little confusing, but trust me, it is not. Let me show you that. So simply move this console dot log below this module dot exports. Save this file, and in the terminal, we again run this file. You can see in the exports object, we have add property and it is set to add function. So if you confuse by the same property name, then we can also change here property name like add numbers. Save this file, and let's again run this file. See, here we get ad numbers property name to add function. Now we can also export more than one functions from the module. So here we create one more function called sub track. Again, we need here two parameters, A and B, and inside this function, we simply return A minus B. Now, can you tell me how to export this function? Right, we simply write here module dot exports dot subtract equals to our substract function. See if the changes and take a look. Let's again run this file. See, here we get this new property substract to our abstract function. Also, it's not necessary that we can only export functions from our module. We can also export variables or objects or array, basically anything we want. Suppose here at the top, we create a variable called name. Equals to let's say code plus U and another variable, lucky number equals to, let's say seven. Now, if we want to export only the name variable, then we can only add here module dot exports dot name equals to name. We don't need to export the second variable if we are not going to use it in any other file. Only export variables or functions which we need to use somewhere else in our application. Now here is one thing. These three lines of code looks a little bit ugly because we are repeating module dot exports. There any shortcut way to write this? Yes, let me show you. So here we can write something like this. Module dot exports equals to, and here we pass object and add all properties which we want to export in this single object. So we write, add, cool, function, add another property, substack colon function, substack and we can set name to variable name. This code and these three lines of code works the same because here we are setting properties one by one. But here we directly set them in object. Let's remove these three lines. We don't need it. Save this file. Let's clear terminal using CLS, and then run the same file and see here we get the same export object as before. So if we know when our property name and passing value name is same, then we can remove this column and variable name. So this add means add column add. Same as we remove this column substract and also column name. So there are multiple ways to write the same code. Save this and let's run it one more time. See here we again get the same export object. Now we have properties in the export object and we can access this export object in any other file in this project, and we will see that in the next lesson. 10. Accessing module in other module: In the previous lesson, we created our math operons module and export three properties. Let me also remove this console line. We don't need it. Now let's see how we can access these properties in the index dot JS file or any other file. Let's remove this previous code. We don't want it. Now to import any module in our file, we have required function in node Js. We call this function here and inside this function in codes, we will enter our module path. So as we can see these both files are in the same folder, so we can write here dot forward slash, which represent current folder. And here we write our file name, math operations dot js. Or we can also remove this dot js extension because if we don't pass extension with our module name, then by default, nodejs will take dot js as extension. What if we have this math operations file in sub folder? Then we have to write here folder name first, and then we add slash file name. And if we have this Mth operations module in parent folder, then here at the place of single dot, we will use double dot. Don't worry with practice, you will learn this. For now, just write dot forward slash math operations. This required function return exports object from this module which we get here interminal. Let me show you. Here, we store this value in variable called math operations. You can take any other name, but mostly, we use the same name as that module. So we don't need to remember another name, so we don't need to remember another name. Here we simply consil dot log math operations, save the changes, and now we can run this index dot js file. Node index dot js. See, here we get the object with those three properties which we added in the exports object in Mth Operations. Here at the place of simple math operations, we can do methoperons dot AD. And here we pass arguments, let's say 20 and 30. Save these and let's run this file again. See, here we get the addition of two numbers. So we successfully use one function from other module. You can see how simple it is to create module and use it in other files. Just we have to export from that module, and then with require, we can use that exports in any other file. So we can use other properties like methoperons dot Substack or methoperons dot Name. But we can see when we need to use any of these properties, we need to write this math Operations dot. So we can use here Javascript topic called object destructuring. Probably you know about this because it is pure Javascript topic. But let's quickly see this. So here we write our object and we want to extract its properties as variables. So at the place of methoperons dot AD, we just have to write EdD. So at the beginning, we write Cs now here, we have to use curly brackets equals to our object name, which is math operations. Now, can you think what we have to write in this curly brackets? We have to write here properties name, which we want to extract from this object as variable. We write here add, which is our function, substract, which is another function, name, which is our variable. Now, at the place of this math operations dot ad, we can simply use this add and we can also add here name. Save this file and let's run it in our terminal. See, here we get 50 and our name. Also, at the place of doing object restructuring in another line, some experienced developers like to do in the same required line. So they simply got this object from here and simply paste it at the place of this math operations name. So we don't need this extra line, save this file, and let's run it again. See, here we get the same result. If you get confused in this objective structuring way, then you can simply use Mth operations dot ad method. It's totally fine. At the end of the day, our code should work. 11. Exercise for own Module: Now it is time for little exercise, so you can revise modules. So here you have to create a new module in your application called Logger. And inside this, you have to export two functions. One function will return current date with this expression, and another function will return current year with this expression. And then you have to console this result in the index dot JS file, same as we do in math operations module, and our output should look like this, give it a try and then watch the solution. So I hope you complete this exercise or at least you try to solve this exercise. Now let's see the solution. First of all, we create a new file called logger dot js. Now here, we have to add two functions. So the first function is current date, and in the GLY bracket, we simply return new date dot two time string. Now let's duplicate this function, select it and press Shift plus alter plus down arrow or Shift plus Option plus down arrow. Let's change the function name to current year and at the place of two time string, we write get full year. Now, do you remember how we export these functions? We use module dot exports, and here we simply set it to object and inside it, we write current date to current date and current year to current year function. Or we can simplify them by removing the same name. Great. So we export these functions. Now we just need to input these functions in our index dot JS file. So at the top, we add required function and simply pass here our module path, which is dot forward slash because this module is also in the same folder and logger. Now we can store its export value in variable called logger. Or as we did in previous lesson, we can destructure it like this. So add here calibrakets and see here we get current date and current year properties. Now, after this console, we add another console and simply call here both functions one by one, current date and current year. Save the changes, and let's run this file in the terminal. It's a node index chairs, and see here we get our output. So you can see how simple and easy it is to create our own modules and access it in other modules. 12. Using Path Module: So till now, we have seen how to work with local modules. Now let's see some core modules or we can say modules which are already available in the node JS. So head over to nodjs.org, and from the header, open its documentation. Make sure here we select other version and select the Ts version because it is the stable version. Here we get all information about node JS, like simple object, console. Also, we have many topics explained and how to use them. We have some core modules like file system. Inside this, they explain all its methods and properties. Also, we have STP module, OS module, path module, and much much more. Here we will see some important core modules which we need to create our back end. If you like to learn all of these, then you can read this documentation. But in my suggestion, I will cover all important modules. Let's start with Path module. Path Module is used to work with file and directory paths. For example, when we want to store uploaded image on our server, then by using this path module, we can give that image proper path for saving them in specific folder. So if you want to merge two paths or other path related things, then you can use this path module. Let me show you that. Also, you can see here, they show us how can we access this module in our application. Same as we are accessing our local modules in the required function. But at the place of file path, we write our module name. So in our application, I simply remove this code. We don't need it now here we write require function, and in the codes, we write node column and our core module name, which is path. In previous node version, we just write the core module name without node column prefix. Also, this will work in current version. I use this previous syntax, you can use any syntax, it's totally up to you. Now, same as before, this require function written exports object from this path module. We have to store them in variable path. Now you might ask why we don't destructure here this object as we did previously? Yes, we can do that same here, but we don't know its property yet. So it's better to not destructure here. Now, let me show you some useful methods of path module. Suppose we want to see some information about specific file. So here we have path dot parse method, and in this parse function, how to pass the full path of our file. But how can we get full path of our file? So in node js previously we seen all files have module object, which we use as module dot exports. Also, all files have another two variables. One is underscore underscore file name, which returns the full path of the current file and underscore underscore Dname which is directory path of current file. Let me show you these two first. So for now, I comment out this path pase method and quickly consol dot log, underscore underscore Dname console dot log, Underscrendscre, file name. Save the changes, and let's run this file. See, here we get the full path of the current directory. Directory means folder, and below that for Underscore desceFlename, we have full path with file name. Now back to our file, we remove this both Console and remove comment from here using Control plus slash or Command plus slash and simply in this parse function, pass Underscredsc file name. We get some details about this file path and to print its result, we simply wrap it with console dot log. Good, save the changes, and let's run this file. See, here we get this object. First, we get root property, which is the root path of the current path. Here in Windows, we get C colon, backward slash. If you are Mac or Linux user, then you will get here forward slash. Next, we have DR, which is directory path after that, we have base, which is the last part of this path, which is index dot Js. After that, we have EXT for extension and last, we get name of the last part, which is index. This parch method is used to get details about the specific path. Now let's see one more useful method of path module which is join. Suppose in our database, we want to store the path at where we store our uploaded image like profile picture. Understoe that profile pictures in folder called uploads in our project. Here we can use path dot join Method. Here at the first, we need the path of current project, and how can we get this folder path? Should we use underscore underscore file name? No, we have to use underscore undisco dirname. At the second argument, we will pass our folder name which is uploads. We will get a path of our project folder and we join Uploads folder at the end of this project path. See what we get. We remove this console and store this path in variable called profile Path and console dot log this profile path. Save this file and let's run this file. See, here we get full path. This first part is underscore underscore, dear name, and we join Uploads folder at the end. I know this is a little confusing, but don't worry when we use these modules in our project, this will all make sense. Now, here you might ask, can we join two parts manually? Why we need to use your path module. So as we know, for a file path, Windows use backward slash, and Mac and Linux user use forward slash. So we get different results in different system. If we manually write path with backward slash, then in Mac we can't find our path. And also, currently, our project is available locally, and that's why we know it's path. But in real world, we deploy our backend application somewhere on the Internet and we don't know the path for that server. So this path module is very useful in this type of situation. 13. Getting Operating system details: Sometimes we need some details of our server operating system like which operating system it is using or how much memory they have, et cetera. For that, we have another core module called OS, which means operating system. So we remove this previous code, and can you tell me how can we access this operating system? Right, we can use it by require function and simply pass here node, column OS. We can use only OS. Now we can store this in variable called OS. Suppose here we want to run a specific code for Windows system and for Mac, we want to run something else. Here we can write if condition s dot platform, this will return the platform name on which this code is running. If st platform equals to win 32, if this is true, then we will run code for Windows. For now, we just write console dot Log, hello, Windowsser. After that, we want to run some code for Mac system. We add s and checks dot platform equals to Dawn. This is the platform name for MacOS. Inside this, we run console dot log, hello MCUser. At last, we simply pass ls and Consol dot log Hellouser. Check this is working or not. See the changes and take a look. See, here we get Hello Windows user, so it is working. Now in OS module, we have many more properties. I don't want to bore you by explaining all properties because that will take a lot of time. But let me explain you two more useful properties of OS module. First one, we can get the total memory of the operating system using this OS module. So Os dot total MM for memory, and we can simply print them using console dot log. Also we have another property called free MM for getting the free memory. So we duplicate this line using Shift plus alter, plus down arrow or Shift plus option, plus down arrow and change this total MM function with freemM. Save the changes and take a look. See, here we get memory in bites. I have eight GB total memory and free memory is almost two GB. You can see this is the importance of node js. Before node js, by using simple JavaScript, we can't get this type of details. So that's how OS module is used for getting information of operating system. 14. File System Module: There is another popular core module which we use for interacting with files. For example, with file system or FS module, we can write the file, read the file, update the file, and also we can delete a specific file. So here in the node documentation, we open file system module. We can see it has so many methods and properties. Let me show you how we can use FS Module. Let's remove this previous code. Don't worry. I will add all this code in separate file so you can look at it later. Here we want to access core module, require code Fs, and we store that in variable called Fs. Now we simply write Fs dot and see here we get the list of all methods. But what is this? All these methods have two variations. One is synchronous or blocking methods, and another is without synkyword which means asynchronous or non blocking. Now, as we know, node is popular because of its asynchronous or non blocking way. We have to always use asynchronous methods in node js. Node give us synchronous method for simplicity. Let me show you one by one both. Here, we want to get the list of files which we have in current folder. For that, we have method called read directory sync, and here we pass the path of directory which we want to read. Period slash which is the current directory, and we store this data in variable called data. And at the end, we simply log this data. Save the changes, and let's see what we get here. See, here we get the list of all files inside this folder. Now let's also see how we can use Asynrns method. So as dot red directory, and same as before, at the first position, we pass our directory path, which is period slash. Now in almost all async method, have to pass second argument, which is callback function, which is the function execute when this asynchronous work will complete. And also, we can see that in suggestions. Now, there are two possibilities for all asynchronous work. We get an error or we successfully complete that work. I know this is a little bit confusing if you are dealing with asynchronous work for time, but don't worry in the upcoming sections, I have complete section for asynchronous JavaScript. You will learn all these in depth. Now in this function at the first position, we get error, and at the second parameter, we get our data. If we get error, then we get null in this data. And if we get our data, then we get null in this error. So for handling this scenario, we can pass her condition. If error is available, then we will log the error. As we will console dot log our data. Simple as that. Now let's comment out this console for synchronous method. Save the changes and take a look. See, here we get again the same data. Now, if you want to verify, we get error or not, then we can change this path to something else, save this and run this file again. See, here we get error, no such file or directory. So now you understand how these acing methods works. Also, don't worry about this complexity because we hardly use these core modules in our project. Currently, I'm showing you just modules, and this file module is little advanced for this stage. So don't worry about this. You will master it when we use them in our projects. 15. Creating Server using HTTP module: Let's see one of the most important core module of node JS, which is SDTP module. SDDP module allow us to create a SDDP server and also for handling different SDDPRquest. As we know, NodeJS is used to create backend for our client application, but currently, we only access this backend in our terminal. What if our front end wants to access our back end? So to interact with web in node, we have SDDP module. Let me show you rectically how we can create server. So same as before, access STDP module using required function and pass here SDDP and store that in variable called SDDB. Now, can you tell me what is this STDP module written? I will return SDDB method. Now, this STDP has one method called Create server which is used to create server for our backend application. Now what we will pass inside this create server function? Simply, here we pass callback function. When someone sends requests to our server, this callback function will run. Let me ask you something. What is the main work of our server? So when user sends request to the server, server has to return response according to data request. So here in our server function, we need the information about user request, which API he or she request for, et cetera. So here, in this function argument, we get request object, which is the user request details. Now here we have information about request. So our server do its process and suppose we want to return response as hello world message. For sending response here in the function argument, we get here response object after this request object. Also, many developers like to write short name, Rg for request and Rs for response. Now to return Hello world message, we write response dot R. And in codes, we pass our message Hello world. In real world, we will return data from here, for now we are just writing message when someone sends request on the server. And here, we have to also tell that this response is end here. So we write response dot N. This will make sure our response process is ended here. Now here we create our server, but we need to start this server on some port. If you no react, our application will run on Local host 5173 if it is created by y. Now, same as that we have to start this server on some port. Let's see how we can do this. Here this stp dot Create server method, return our server object, we store it in variable called server. And after this at the bottom, we write server dot LISN. And in this function, we will pass our port on which we want to start this server. Many developers like to run server on 5,000 or 3,000. But you can give any port, make sure that port is not used in your system. Here, I like to use 3,000. In real world, when we deploy our server, then this port will replaced by our Bend domain name like catwis.com or tasrag dotben.com, et cetera. Also, in this function, we can pass another callback function. This function will run when our server start successfully. Here we simply write consol dot log server start listening on port 3,000. Save the changes and let's run this code because without this code running, how server will create node index dot js. See, here we get server start listening on port 3,000. If you're using Mac and you use port 5,000, then you might get error for 5,000 port is already in use because in Mac ARP receiver surveys running on this port. Can use another port like 5,001, 5,002, or you can even use 3,000. There is no rule for port number as long as the port is already in use by another service on our system. Now to check this, we need to send requests on this port. So open a browser and simply write here URL, Local host Column 3,000 or your port number. See, here we get our message, Hello World. So we successfully create our server and also start this server. So whenever someone sends requests on the server, this function will run and print this message simple as that. 16. How to handle different routes: Now currently we are sending requests on the port route route, which means home route. But in real world, user can send requests to local host Column 3,000 slash About or slash products. So we have to also handle these different routes on our server. And for handling different routes, first, we need information for which route user sends request. And for that have here request object. We write here condition I request dot URL equals to in codes, forward slash. This simple forward slash represent the root route. In the CL brackets, we can simply move this response dot write function withholding alter or option, and up arrow. After that, we want to handle, let's say about route. So here we add si request dot URL equals to in codes about and if it is true, then we simply return another message response dot right. This is about route. Like this, we can add as many requests as we want. And after all routes, we will pass, which means user pass routes, which is not handled here. And that's why here we return simple response dot right, route not found. Also make sure this response dot function called at the very end of this server function. Save the changes and back to our browser. If we change our URL to slash about, can you tell me what we will get here? Let's see. See, here we get the same hello world message because in our terminal, still our old code is running in which we didn't handle routes. To run this new code, we have to again run our application. In terminal first, we will stop the application by pressing Control plus C in Windows and Mac both. After that, we again run node index dot js. Good, we get here, servers start listening on port, and in browser if we refresh our page, see, now we get here message. This is about route. And if we try to request any other routes, then here we get route not found. That's how we handle different API routes using SGDP module. Now imagine we have 20 different API routes and to handle them, we have to write 18 more sf block. And if all those routes has hundreds signs of code, then managing our own server will become so messy. So in the real world, we will not use this SDDP module. Or that we have very popular third party module called Express and Express has many more benefits than this SDTP module. Also, using Express, we can divide our routes in different files, so we don't get confused when we have to make any updates or we want to add new functionalities. I explain all these modules so you get little understanding how node is working and you get comfortable with some JavaScript syntax. I hope you enjoy this section, see you in the next section. 17. Section 03 - NPM Introduction: Come to the third section of the ultimate node JS scores. In this fun little section, we will see all about node package manager or in short NPM. So what is node package manager? Node package manager is a tool which help us to manage packages or libraries for our node project. In simple words, NPM is like a big warehouse for developers. In this warehouse, developers store their JavaScript code so other developers can search that code and download the reusable code in their project. Let me show you that. So head over to NPM. Js.com. Here we can search our package or library name. Package or library means a piece of reusable code. For example, in previous section, I told you we will use Express Library for creating STD server. See, here we get many results for this search. Simply, we open this Express package. See at the left side, we get basic documentation, how to use it, et cetera, and at the right side, we get information about the package. First of all, at the top, we get installation command, which you'll see in upcoming lesson. Next, we have Github repository link so we can see the code and also we get link of their official website. Here we can see this is the monthly downloads of this package. By this, we can see the popularity of this package. Also, we get version information and many other things. So on NPM, we get packages for almost all functionality which we want to add in our application. And the amazing thing is this all packages we can use for free. So there are premium packages, but it's rare we purchase package. Actually, I didn't purchased any package till now. So in this section, we will see commands for how to install different packages. Also uninstalled packages, install developer dependency, update some packages, et cetera. So by this one little section, you will get comfortable with NPM commands and you don't get confused about them. They are extremely simple and easy. So let's start this section. 18. Creating Package: So as we see in previous lesson, we use as many packages as we want in our project. Now when we install any package, that package has a bunch of files and folder, which we will download in our project and store it in folder called Node Modules. Now just imagine we install ten or 20 packages in our application. All those files will store in this node modules folder. When we want to share our project or we want to upload our project on Github, then we don't upload this node modules folder because it will increase the project size and also it will increase the number of files. So we don't upload node modules folder. Now you might ask if we don't share this node modules folder to someone, how they know which packages they have to install. To solve this issue in our node project, we will create one file called package dot JCN. In this file, nodes store all the main information about our project. So whenever we start working on any node project, first and foremost thing we do is we create packaged Gs and file for our project. Let's see how we can create package Gn file. So here I create a new folder called NPM Dash Commands and open that folder in vis code. Good. Now here, first of all, we have to create package GSN file for that, we open our terminal using Control Plus Batak, and here we write NPM, init, and hit Enter. See, this utility will walk you through creating a package sn file. At the bottom, it asks for our project name. If you want to change it, then you can write a new name here, but make sure you use small letters and also without space. I am happy with this current name, so I simply hit Enter. After that, it will ask for version name. Again, we don't want to change this default value, so we hit Enter. Now here, we can write our application description. For now, I just skip this. Next, we have entry point, which is the default file name of our project. So when we deploy our application, that platform will know which is the main file of our application. After that, we have test command, Git repository, then keyword, author, and license. Hit Enter for all of this and see here we get this object which is going to add in the package to JCNFle it is asking, is this okay? If you're okay with these details, then we can simply write here, y or yes. And done. See, here we get package JsNFle in our project folder. If you open that file, see, here we get this object with application details and in future, we can also change these details. Now, if you pay little attention, when we are giving answer to package GSN file, we didn't actually change anything and still we have to go through by all those questions. Is there any shortcut trick for this? The answer is yes, we have shortcut com creating packages and file. Here, let's delete this current package Gs and file. In the terminal, previously, we write NPM in it. With that, we need to answer all those questions. But if we want to skip those questions, then we write here NPM in it Y for all, yes. And done. See, we get again package DsnFle in just a second. And also object is same. To sum up, when we start any new nodejs project, first of all, we need to create package Gn file with NPM init command. 19. Installing package in project: In the previous lesson, I told you this package GSN file has application information with the package list, but we can't see any package name here. It's because in our this application, we didn't install any packages yet. So let's install some packages. For that, we need to run one command in the terminal. Is really simple. Just we have to write NPM install, or we can use here shorthand, which is just I space. Here, we write our package name, let's say Express. Also, you will get this command at the page of that package on NPM website. You can copy from this also, and here we hit Enter. See in our projects folder, we get node modules folder in which our all third party packages saves their files and folder. And if we open that, see, here we get many folders and many files. Don't worry about that because in real world, we never ever open this folder. Either we create that folder, we delete that folder, but we never open that folder, don't worry. After that, we also get the package log dot JsNFle. Packageog dot JsNFle is used to log dependencies to a specific version number. In other words, the package log dot JsNFle makes sure every developers and also the deployment system uses the same version of package to avoid problems. Also, don't worry about that. We hardly touch this file. And if we see in the package dot JcNFle here at the bottom, we get new property called dependencies, and in that, we get all our dependencies with its version. Dependencies are what our projects depends on. Without these packages, our application can't work, and that's why we called it dependency. This is the version of our Express package. If we install another package, then that package will addhe in this dependency list with its version. Now this version is the latest version which developers deploy on NPM website. But sometimes developers by mistakally deploy bogged version or new version, introduce some new syntax. In that case, we can also install older version of any NPM package. So here at the right side, we have version Stab. See, here we can see the full history of this package. We can install any of these packages. Suppose we want to install this 4.18 0.1 version. So we click on that version. It will open its homepage for that specific version. And we can see here version is changed, and also installation command is changed. They add AdSign and after that, they write package version, simple as that. So back to VS code here, our current version is this. Now, we copy this command from this site and simply paste it in our project terminal and hit Enter. C version changed. So that's how we install packages with NPM I package name command. Also, here we can add multiple packages names. And if we want to install specific verson then we write NPM, package name at the red version number, and that's it. That's how simple to install package in node project. And after installing the packages, we can start using them in all JavaScript files of this project. 20. Uninstalling packages: Now let's see how to uninstall package. But before that, let's install another package called Mongo DB. Tell me which command we use. We use NPM install or I, and then we write our package name Mongo DB. You are doing real great. In this package dot JCNFle, you can see another package in the dependency. Let's try to uninstall this package. For that, we need to write NPM, uninstall, or we have also shorthand for that, which is UN. Then we write our package name which is Mongo DV. This command does two things. First, it will remove that particular package files and folders from the node modules folder. Second, it will update config files, which is package JSN and packslogt Json. By that, in the future, our application don't install unnecessary packages. 21. Install package as Developer Dependency: Now sometimes in our project, we want to install package just to use in the development environment, not in the production. For example, we have some testing packages which used to test our code implementation. We don't need testing packages in our production environment. It will unnecessary increase the server size. In the node Jazz, we can install packages at the developer dependency or in short, dave dependency, which means that package will only add in our development environment, not in the production. So in our application, let's install one testing package as Do dependency. For that, we write NPM. Here we write our package name, which is Mocha. This is the normal command for installing package. Now for installing package as Do dependency, we have to add option here, d s Dev and hit Enter. Now let's verify this. Pun package dot JCNFle at the bottom, we can see dev dependencies, and in that, we have our package with its version. We can install any packages as dev dependencies, we have to use Dev at the end of install command. But keep in mind it will only add in the development environment. Also, if we want to uninstall dv dependency packages, then we use the same command which we see in the previous lesson, NPM Uninstall or UN package name, which is Mocha. And done. 22. Outdated packages and update them: Let's see some useful commands of NPM. Sometimes in our application, we install some packages we might get outdated and NPM has its newer version. For example, in this section, we install previous version of the Express package. Now, how can we identify which packages has updates? For that, we have one command in NPM, which is outdated. We write NPM outdated and hit Enter. And see, here we get the list. We have package name. Is current version, wanted means latest version of the package that satisfy the version range. Latest version, which is the latest table version of this package, location, which is the location of this package, which is in the non module express folder. At last, dependent on which is the project or dependency that is depend on this package. By this, we can quickly see which packages is outdated in our project. Now currently we get only one package, but imagine we are working on old big project and here we get many outdated packages. Now to demonstrate that, let me install another package with older version. We write NPM install Mongo Debi at the rate 4.14 0.0. Hit Enter. Good. Now we again run NPM outdated command. See, here we get our both packages. Now you might ask why wanted version and latest version are different? What is that meaning? As I told you, wanted column sources, which is the latest version of the package that satisfy the version range. Currently, we have version 4.14 0.0 in our project. It's version range only version four related. For example, 4.15 0.1, 4.16 0.0, 4.17 0.1, et cetera. This type of version is the version range for 4.14 0.0, not 6.15. But you might ask, what is the problem to upgrade our version to 6.15 0.0 lets version? We can do that. But when developers change version number like version four to version five or version six, then they might done some updates which can give you error for old code according to version 4.14 0.0. That's why we always update our package to this wanted version, not by latest version. By that, we will not break our application. Now we want to update all these outdated packages in single go. We have another command for updating outdated packages. The command is NPM update. That's it. It will update all packages to its latest version within the specific range, but it will not update package dot Json and packago Json files. See, in the package GSN, we still has our old version called Express package. Now, until we update package dot JSN or packaglot JCNFle there is no point to install latest version. It's necessary, we need to update package dogs and file. For that, we use another package uploaded on NPM, which is NPM check updates. We write NPM, I and here we add G for globally install this package in our system. In the other node applications, we don't need to install this package. It will globally available in our system. Here we write our package name, which is NPM check Updates. Make sure you write the same name with dash, not underscore. Also, if you're using MG, then at the start of this global command, you have to add pseudo prefix. Otherwise, you will get error and after that, enter your system password. Now we can simply run NPM check updates. See, it checks the package dot JCNFle and says our Express and Mongo DB has updates. Here it is showing this latest version, but we want to update our package with wanted version. So we have to write here NCU, which is the shorthand of NPM check updates. T for Target. We target minor, which are the wanted versions. This will return only major versions. See, here we get the wanted version for both packages. Also at the bottom, it suggests run NCT minor to upgrade package J and file. We run NPM check updates, or we can write NT, minor and hit Enter. C, it changed the version in the packages and file. Again, it suggests to run NPM install to install new versions. We write NPM install or NPM I and hit Enter and done. Our all packages are updated, that's how we identify outdated packages and how to update packages to its latest specific range. So our application don't break by new package version. 23. Remove unused packages from project: Sometimes in our application, we might install so many packages at the beginning of our project, but some packages we really don't use, so we can remove those unused packages because it will take unnecessary space in the production. So forgetting the list of unused packages, we need another package called DP check, which is the dependency check. So we write NPM IG depth check. Again, we are installing this package for global level. In all application, we can use it. Also, if you are Mcuser, make sure you add sudo at the beginning of global package command and enter your system password. Now you can simply run here dep check, and it will return the list of unused dependency and also unused dab dependency. Currently, we didn't use any dependency or packages. That's why we get all third party packages as unused. By using NPM uninstall or UN Express Mongo DB, we can uninstall all packages. Great. Now if we again dap check, then we don't get here anything, lovely. That's how we can remove unused packages from node application. That's all about node package manager or NPM. If you want to quickly revise what you learn in this section, you will get summary PDF at the end of each section, so you can download it and recap what you learned. Now, from the next section, we will start building our first real No Js project. 24. Section 04 - API vs REST API: Welcome to the fourth section of the ultimate node JS course. In this section, we will start working on our first project. So we start with basics, What is RS API, set up our server using Express JS, then we will create different types of STB request, get, post, put, and delete. Also, we see data validation and much, much more. So let's start this section. Now as we know, API stands for application programming interface, and it is the way for two programs communicate with each other. Remember our restaurant example, let's see another real world example. Imagine user wants to register on our website, so he or she fill the form and then submit it. The moment they submit, we call API for register a new user, and in the back end, we create a new user. Like these, we can create many APIs for logging the existing user, get all products list, add products to cart, delete products from cart, et cetera. In simple words, API is used to transfer data between front end to backend and back end to front end. We already know that. Now you might ask what is rest API. Rest API stands for representational state transfer API. Rest API is a specific way of building our simple APIs. Don't worry about its name. It's very simple. Rest API is the same API, but we have to follow some rules to build that API. If we follow some rules, that simple API becomes rest API. Now let's see some rules which we have to follow. Make rest API. One rule is we have to define separate API URL for each piece of data. For example, suppose we are creating API for user related operations like register user, getting the information of single user, et cetera. In this case, our API should be our domain name and then slash user for register. And if we want to get information about single user, then we create API URL like slash users 123. Here 123 is a user unique ID. Same as if we create API related to products, then our URL should be like this slash products, slash products, slash 123, slash products, slash Add to cart, et cetera. So by simply looking at this API URL, we get the basic idea related to our APIs, and by that, we can easily do changes and our application stay clean. Another rule is different types of actions like reading, adding, updating or deleting data. Should use specific SGDP methods. Now you might ask what are SGDP methods. So as we know, SDDP stands for hypertext transfer protocol, and it allows our front end to request and receive web pages and other resources from servers using API. So only because of SGDP we are able to send and receive data from backend using API. Now, this SDDP has five main methods. Get, post, put, patch, and delt. Let me explain you this one by one. First one is the Get method. We use Get method when we want to only get data from the server. For example, we want to get all users details, or we want to get all products details or we want to get single product detail. In this case, we define our API with GT method. For understanding these methods, we will use analogy of library. Get method is like asking a librarian to show you a book or multiple books. Don't worry about implementation. We will see all methods step by step in this section. Second, we have post method. We use post method when we want to post or send some data from front end to create a new data in our server. For example, for register a new user, we have to send user data from the front end and that will create a new data in our server. Think it's like we're giving new book to librarian for at the book in library. Next we have put method. We use Put method when we want to update an existing data on the server with new data. For example, if you change your profile information on a website and save it, then a put request is sent to update your profile with the new details. Think it's like giving librarian an updated version of a book to replace the old one. Next, we have page method. We use page method when we want to update a piece of small data, not entire data. Example, if we want to update just our email address in our profile without changing anything else, then a page request can be used. Think it's like we are giving librarian just the updated pages of a book to update rather than replace the whole book. Imagine, here we have user object in our server. Want to update, complete this user object, then which method we will use, we use put method. And if we want to update just a password of this user, then which method we will use, we will use patch method. You are doing really great. Put method is used for whole data update, and patch method is used for little update in the existing data. Last method is delete. And you guess correctly, we will use delete method for delete data from the server. For example, when we delete a post or a comment on social media, then a delete request is sent to remove it from the server. And for that, I don't think we need library analogy, right? And also, it is not practical. Think it's like asking libraries remove a book from library. You can see SGDB methods are very simple. We will use these five SGDP methods to define our different types of API. These are just few rules we currently see, but don't worry, we'll learn all these rules as we build APIs. Now you might ask why we need rest API. Why we need to follow rules for building API? By following any rules, we can make things organized, and that's true for RS API also. Rules will make our API more organized. Also, by following REST API rules, we create a simple and easy to use API because they use specific SDDP methods for doing specific types of work. Also, with rules, we can create a clean and maintainable API, which any developers can understand and start working on them. For now, don't worry about rules. As I said, you will learn these rules while you create APIs. Celeste start winning our first node JS project. I'm very excited and I know you are too. 25. Planning API List for Project 01: Now before we start any project, it's better to roughly plan about Ted project. So as we know, our first project is about managing the task and here how its front end looks like. Also, this is the first project of my React JS course, and we will build this project backend as our first backend project. Don't worry, we are not going to create here front end because our main focus is on the NodeJS and building the best backend for our applications. From the front end, we just need to call APIs. Now you might ask, how can we plan NodeJS project? It is very simple. This is the method I used for planning my Bend project, even big projects. Instead of building project first and then doing major modifications, it's better to spend a little time on planning before we start our project. For Ben project, if we create the list of APIs, that's very useful because Bend is almost all about APIs. For this project, first, we need the list of all todos, one API for getting all todos. After that, we need to create API for adding a new task, and after that, we can update the single task details, one API for updating the task, and at the end, we need to delete single to do, another API for delete specific task. Currently, we know we need these four APIs, and we will create two, three extra APIs for practice. If while building project, we need to create more APIs, then we will create more APIs. There is nothing wrong about that. This is just a rough plan for reduce the confusion. 26. Setup a new application: Now let's create a fresh application for our project. So open the folder in which you want to create project, and I name it as task track and simply open this folder in the VS code. This is the name of our project. Is it sounds good? I hope it is. If you have better name, then you can also use it. It's totally up to you. Now what we have to do for creating no JS applications? Do you remember we just did that in our previous section. Yes. Simply, we open our terminal and initialize our project using NPM in it for As we will use y here. See, we get pgsNFle with some default configure. Here, we can see our main file is index dot js, which is the file runs when we start our application. Let's create index dot js file, and that's it. Here in this file, we will write code for our back end. 27. Build server using Express: So in the previous section, we create our server using STTP module. The problem with the STTP module is we have to define our different API endpoints in these I and LSI statements, which is not very clear and also not easy to maintain for big projects. So that's why we use very popular package or module called express dot js. Express Dogs is minimal and flexible for creating better node applications. In simple words, by using express dot js, we can simplify our routes. We can easily handle STIP request and response, middlewares, and much more things. Let me show you something. Here is the Express package on NPMJS website. You can see its weekly downloads are almost 37.2 million, which is crazy and almost 90% of NodJS projects developers use Express package. It is very important Master Express. First of all, let's install this module in our project. Open up terminal and write and pm Install Express. At the time I'm recording this course, its latest version is 5.1 0.0. You want to get the same experience as I'm getting, then you can write here NPM install Express aerate 5.1 0.0 and hit Enter. Don't worry about Express. It is really simple package. D. Now we want to use this Express module in this index js file. Can you tell me what we have to do? Right, we will input the express module using require function, express, and this required function returns a function. We simply store it in variable called express. Now, to create an express application, we call this express function here, which returns a object and we store it in variable called application or app. You can give it any other name, but probably all developers called it app. Let's go with app. Now in this app object, we get many useful methods. For example, we have here app dot get app dot post, app dot pot. App dot patch, app dot DLD, et cetera. Do you remember where we see these five methods? They are SDDP methods for creating different types of API. If we want to define our API for SDDPGt method, then we use app dot GAT. If we want to define SDDP delete method, then we use app dot DLD. Same as we can create post, put and patch request. The way to define all these five methods are the same. Still, we will see all methods in this section one by one. For now, let's start with GAD request. In this GAT method, at the first parameter, we have to write our API endpoint name. Suppose we want to define G API for URL, SGDP, Column double slash, local host, Column 3,000 slash Tudo. Now what is our endpoint in this URL?Tudos is our API endpoint. That's what we have to write here at the first parameter. Make sure we addheFward slash first. Otherwise, this will not work properly. Now, what if we want to define get API for URL, SDDP column double slash localised column 3,000, which is the root URL of our website. At that time, we can adhere only forward slash, which represents root end point. Now we have to define what will happen when our front end sends requests to the end point. Do you remember, let me show you. Here, we pass callback function, and in this, we get two objects, request and response. This request has all details about URL request and with this response object, we can send response related details. We already seen this in STP module lesson. Now what we want to send when someone sends request on this API. For now, we simply return a text response dot SEND Task Track project. When someone send Get request on this endpoint, this function will run and then it simply returns this text in response, simple as set. By these two lines, our Express server is created, but we have to run or listen this server on some port. If we don't listen our server, then our API will not work. Here at the end, we write app dot L ISE and simply here we pass our port number at the second parameter, we again pass Callback function, which will run when our server started listening on this port. Here we can simply consol dot log server is running or listening on this port 3,000. Save the changes and let's run our index dot js file. Write node, index dot js. C Server is listening on the port 3,000. Nice. Now back to browser and run Local host Column 3,000, which is the root URL and see here we get Task track project text, which we send from our server. You can see Express makes our code really simple. We can compare our current code with the previous SGDP module code. Express makes it really simple. Also, this is our first API. That's why we written only text in response. Now, as we move forward in our project, real thrill will start. 28. Exercise for Creating Express Server: It is time for little exercise. I want you to remove all code from the index dot JS file and again create Express server and create API for root and point. By this exercise, you will get familiar of making Express server. Literally, it will take only 1 minute. Try to complete this exercise and then watch the solution. Okay. I hope you solve the exercise or you tried to solve that. Now let's see the solution. First of all, we need Express module in our file. Require Express and store it in variable called Express. This express is a function, so we call it here and it will return our server object or application object. So let's store it in variable called app. Here we create our Express server using these two lines, but we have to listen our server only then we can run our API. So at the end, we simply add app dot Lisen and at the first parameter, what do we will pass? Right, we pass port, which is 3,000. And at the second parameter, we pass callback function and inside it simply console dot log server is running on port 3,000. One thing is, I listen server before adding API because many times I forgot to listen server, and it will waste a lot of time. I always listen the server as soon as I create the server. Now, in between, we can define our API anything. So for Get request, we add app dot GAT. At first, we add our API and point, and then at the second parameter, we ad callback function, which has two parameters, request and response. Inside this callback, we simply send text using response dot SNG. This is Task track project. Save the changes, and here we have to stop our application from terminal because it is still running old code. We again run node index dot js file. See, server is listening, and in our browser, we get the updated text, very simple. 29. Creating API for Getting all todos list: Now let's create API for getting all todos list. Can you tell me which SDP method we have to use? Right, for getting the data from the server, we use Get DP method. So here we write app dot GT. And let's say we want to give this API name todos. So we pass here slash todos, and after that, at the second parameter, we pass callback function, which has two parameters request and response. See, for all APIs, this structure will stay the same. Only this SDP method change, this endpoint change and logic inside this call web function will change. That's how Express JS makes our project simple and clean. Now, currently, we are not going to work with a database because we don't want to add extra complexity for our first project. We will learn all these things step by step. So don't worry about database. Now here, we have to send all todos array. At the top, I define one dummidata called todos array and simply add some todos in this. Here, every todo is object with four properties. ID, let's cite it to one task, which is a text of task. Let's create all APIs for project one. Tags, which are the tags related to task, which is an array, not just comma JavaScript. And status to do. These properties, ID, task, tags, status is defined by noches developer, which means you what you want to call it, how many properties you need, these things you have to decide based on which data we want to store and which data we don't want. Now let's duplicate this object two more times using Sift plus alter plus down arrow or Sift plus Option plus down arrow. We change this ID to two task to create EPI for list of all to do tags, no Js and status to doing. At last, we simply change ID to three task to plan project one, text JavaScript and status to done. Want to simply return this array as response when someone sends Gut request to API which slash todos and Point. What we write here, we, we write response dot SN and simply pass our todos array. Save the changes, and let's verify this API is working or not. Open terminal, close the current running server using Control plus C, and again run this file. Now in the browser at the place of root website, we simply call slash Todos and Point. See, here we get our array. That's how simple to send data from the back end using G API. 30. Setup nodemon auto restart: Currently, when we do some change in our project, we have to close our previous running server and restart our application, which is really annoying. For automatically restart our application, we have one package called nodemon. It is really useful. Open up terminal and write NPM install or IG nodemon. Here we use DSG for installing this Norman package globally. Otherwise, we have to install nor moon in every node project. Also, if you're using Mac, then for installing global package, you have to write sudo at the beginning of the command and then it will ask for system password. Now, how can we run file using node one? Let me show you. In the terminal, previously, we are running file using node, index dot js. Now for nod M, we write nodemon index dot js. Simple as that. See, here we get our node M version. Or restarting, we can enter RS. Also, it is telling us watching Path period, which means root of this project. After that, it is watching extensions like Js, MGs, Cgs, JSON, et cetera. An file which have this type of extensions, Nod moon is constantly watching those files, and if something changes in those files, it will restart our application. At the end, see, nodemon is also running Command node index dot js. By using nodemon, we don't have to restart our application. It will automatically restart when we change something in those files with those extensions. 31. Environment Variables: Now currently we are manually setting the pod of our server. But in the real world, that pod is set by environment in which our application is running. Specifically, it's managed by the hosting provider or development platforms like render, Heroku, AWS, et cetera. When we deploy our application, on these platforms, our 3,000 port might be already used by another server. At the time, if we hard coded our port, then our server will not run on that port, and it will give us error in the deployment. So what is the solution here? It is really simple. We will check one condition. If in our application environment, port variable is defined, then we use that port variable, else, we use our hard coded port. Let me show you it is really simple. So here, before we listen our server, we create a variable called port equals to now here, how can we check our server has port in its environment or not? So for that, we have one object called process dot ENV. This ENV is for environment. In this environment, we get all variables which are set by hosting platforms and port for Port variable. So if any hosting platform want to set different port, then they will store them this process dot Env dot port variable. That's common convention. Also, all environment variable name is all capital letters, and that's why we also give this variable name as all capital port. So just by looking at it, we know it can be environment variable. If this process dot nw dot port is available, then no issue. But if it is not available or set, then we have to pass our hard coded port value. We adde or operator, which is par symbol two times, it is the key above enter or return. Here we pass our port, which is 3,000. Now let's pass this port variable at the place of this hard coded port, and also we will change this console message. Let's make this string as template string using acti because in template strings, we can easily access variable and change this 3,000 with dollar coli brackets, pot. If this environment port is available, then we use it or if it is false or null, then we use this 3,000 port. Simple as that. Currently, in our application, environment Port is not set. That's why our application will run continuously on port 3,000. Don't worry if you are a little confused about this process dot ENV, we will see it in details in the upcoming projects. Let me give you one shortcut for setting up node application. First, required Express, create express application, create this port variable using this expression and listening the express application on the port. These four things will stay the same in all node applications. Yes, we can add more functionality in other lines, but nothing will change in these four lines. 32. Route Parameters & Query Parameters: Previously, we created API for getting the list of all to do in our application. But what if we need to get the information about only single to do like to do with ID one or ID three. For that, we need to pass ID in APi URL. Our APIURL look like this. Todos ON, which means we want to fetch one to do information whose ID is one. Type of variable which we pass in our URL is called a route parameter. It is very important for providing the specific information about API request like ID, status, date, anything. Let me show you how we can set this type of API URL and access the route parameters. We add new GAT API endpoint to slash todo slash. Now here for defining route parameter, we use colon and give our route variable name like ID. This ID is our route parameter. We can call it anything like todo ID, but ID is short and sweet, so we go with ID, and that's it. That's how we can define route parameter in our API URL. Let's access this route parameter in our API logic. Again, we adhere callback function with two parameters, request and response. Now, inside this function, what do you think? In which object, we get information about our route parameter, request or response. Eight. We get information about route parameter in request. So request dot PAMs. In this perms object, we will get all route parameters, and we can access it by dot ID. See, here we get also auto suggestions. Now let's simply send this ID in our response dot SND save the changes, and back to our browser. Head over to local host, Column 3,000 todo slash one S, here we get ID one. We are successfully getting the route parameter. Now here is one thing. We can also pass multiple route parameters in our API. For example, we can pass task status todo. Now in the back end, we add here route parameter. How can we do that? Right. We add slash Clan status, and how can we access route parameter? Right. We use request dot Perms dot status. Let me show you whole route Perms object. Save the changes, and back to browser, we pass here status value after our ID value. Make sure the order is the same as we define in our API, which means first ID and then status. See here we get the params object with those two properties which we define in API. Now you might have curiosity. What if we don't pass here status? Let's also see that. Remove the status value and see, here we get cannot get to do one, which means our server didn't found ABI with this URL. If we define route parameters in our API, then make sure we will pass all route parameters in right order. There is another way to pass data in URL, which is by using query parameters. If you're using websites, then in URL, you might seen question mark and then pass some types of variables like shot equals to date and order equals to a C for ascending, et cetera. These are the query parameters which is used for passing data in URL. Now you might ask, what is the difference between route parameters and query parameters? Those are used to pass data in URL, but route parameters are used to pass data which is most required where query parameters are used to pass data, which are additional or optional. In simple words, in our API, if front end didn't pass route parameters, then our API will give us error. But if we didn't pass query parameters, then our API will not give us error. It is an additional details. For example, if we didn't pass todo ID or status, then it will give us error that API not found. But if we don't pass these variables after the question mark, then we don't get error. Now let me show you how we can access the query parameters in our API. For that, we don't need to change anything in the API URL. And directly access them in our callback function. For query parameter, we have another object in request, which is request dot query, and that's it. We don't need to do anything in our endpoint. Save the changes and take a look. See, here we get the query object. Request dot params is used for route parameters, and request dot query is used for query parameters. We will use them a lot when we build complex APIs. They are very useful. 33. Get Single Todo by ID: Now let's see how we can return single to do by its ID. For that, what we use route parameter or query parameter, we will use route parameter because that information is most required. So we remove this class status from our endpoint, we don't need it. In the Colvey function, we need to return the single to do, which ID is the same as our route parameter ID. First of all, let's store the route parameter in separate variable. So Cs to do ID equals to, how can we access route parameters? We request dot params ID. Now we have to find a single to do from our todos array which ID is same as this to do ID. That we use one JavaScript array method, which is find. Todos array dot find, and inside this fine method, we pass callback function, and here in the parameter, we get the single to do object a So this T is this single object in the Tds array. And we return here condition if t ID equals to our todo ID. If you don't know this fine method, then let me explain you in short because it is pure JavaScript concept. So this fine method will check our Tudos array, and first, it will pick the first object of the array in this T variable, then we check the condition. T dot ID is same as where to do ID. If it is true, then this fine method will return that single object. So we store invariable cons to do. A, if this condition is not satisfied, then it will set T as next object and then again check the condition. And that's how we can find single to do using this fine method. Let's sent this to do in response dot SN method. Save the changes and take a look. Let's remove these query parameters and so status value, and here we don't get anything. Why? We pass ID one, and in our todo array, we also have to do with ID one. Then what is wrong? Let's try to console the single todo. Gave the changes and refresh the page on browser. Now in our VSCO terminal, where we are running our server, we get our consoles. See, here we get undefined. So we cannot find todo from our todos array, and that's the error. May this error occur because we are not comparing the IDs properly. Let's also try to console this todo ID type using type of do ID. This will return the type of to do ID, save the changes and refresh the page. Back to VS code and see, here we get undefined for single to do, and we get type string what to do ID. That's why we are not getting single to do because here our todo ID is integer and we are comparing it with the string. So we have to convert this Td ID string into integer. So we can wrap this request dot perms dot ID with parse integer. Pass integer function will convert our string into integer. Save the ings and take a look. Refresh the page and see, here we get the single to do object with ID one. If we pass here ID three, then we get here to do with ID three, so it's working. Good. Now you might ask in the route parameter, we are passing one as integer. But why in the back get it as a string. So the truth is whatever we pass in the URL, it is passed as string. So if we want to pass something as integer, then we have to convert it in the back end. We can't pass integer value using route parameter, and it is also true for query parameters. So always remember when you define route parameters or query parameters, then you have to convert its value using parse integer or parse float method. I intentionally create this error to show you what might happen we create API and Xs ID in the route parameter. 34. POST API for Adding new todo: Now let's create post API for adding a new to do object. As we know for creating new data on server, we use post API. Also in post request, front end will send data to the server. For example, here we create post API for adding a new todo. So our front end will send details about the todos like task, tags, and status in the body of that request. Out this information, how can we add new todo in our todos array? Don't worry, let me show you this practically. So here we define post API using app dot post, and at the first argument, we pass our endpoint. Let's pass slash todos at the second argument, we pass callback function with two parameters, request and response. Now you might ask these two endpoints are same. How can we use these APIs individually? So here we can see this API used Get method, and the second API is used post method. When front end send API request on this endpoint with G method, this function will run and if frontend send API request on the same endpoint with post method, then this function will run. We will see how to send post request in just a minute. Now, as we know from front end, we send data in the request body and how can we get information related to request in this function? We can use this request parameter. In this request, we will get all information about that particular request. Here we have request, and in this request, we have property called body. This body has all data which front end sends with the request, which is our todo object, we store it in variable called todo. And after that, simply consol dot log this todo, and also response dot send this to do. Now, let's taste, we are getting data in our todo variable or not. Previously, we are sending simple Get request from the Browser URL because by default browser send Get request to the URL, but we cannot send other SDDPRquest using Browser URL. For that, we need front end code we can use API tasting software like Postman, or we can also use one VS code extension called Thunder client. From this three option, installing VSCode extension is much easier setup. So in this course, most probably we will use Tender client and Postman both because we're tasting Advanced API, we need Postman. But don't worry, both interface are same. Main thing is we should able to taste our API, simple as that. Head over to extension final from here, and search Thunder client and install. Now in our panel list, this tender client icon is added. So let's open it. And here we can taste our APIs for our project. So first of all, we enter our API URL, which is SDDP, column double forward slash Local host, Column 3,000 slash Tu Dos. And which method we need, we need post method. So we select post from here, and now we have to pass Todo Object in our request body. So for that, we select here body and in the JSON option, here we will pass our data in object. First field we need is task. We have to pass field name in double codes and also we have to pass value in double codes. This is new task. Also, if you can't see these fills properly, then close this penal by using Control plus B or Command plus B. After that, we need another field which is tags, and we pass here array, and in that we pass two values SGML, and CSS. Last fill status and value, let's say, to do. Now here's one thing. This fill name, which is this task, tax status, these names are set by the backend developer. Whatever name Bend developer defined, front end developer should send data with the same field name. Otherwise, how in the back end we fetch data from the body of the request. For sending this post request, we click on the Send button. See, we didn't get anything, and if we check our terminal, then also we get undefined. Why we are not getting the data in our request dot body object, what we are doing wrong. When front end sends post request, it sends data in the body of the request in JCN format, and that's what we also did in our testing request. By default, Express server does not know how to automatically read and understand that JSN data. For Express, we need a translator which will convert that JSN data in a simple Javascript object because we cannot directly work with JSN data. We need to convert it in object or array, which our Javascript can understand. For that, we have one middleware in Express, which will work as a translator. So after the todos a variable, we add app dot U, and in that, we call our middleware express dot JSN and that's it. Make sure you add this middleware before our APIs, and also you have to call this express dot JS and middleware. Otherwise, it will not work. Currently, without this express dot GSN middleware, we are getting request dot body as undefined. Now let's save the changes and again, send post request. See, now we get our request dot body, same as we send this object. So this is the importance of express dot JsN middleware. Now we have to just add this new todo in our todos array. So we use here simple array method, todos array dot push. This will add new data at the last position of the array. And here in the push method, we pass object because all our todos is in object, and we have to follow the same object structure for the new to do. So first of all, we need ID and how can we get the we didn't pass it from the front end. So for ID, we can do something like this. We will get the last to do ID and increase it by one. So to get the last to do of the list, we write todos array in square packet todos array dot Length, which is currently three. But we know array index start with zero. So we have to do here length minus one. So this Tds array in square bracket, Tds array dot length minus one is our last to do object, and we want to access its ID. So we add here ID and simply increase it by one. So if our arrow length is three, then three minus one, which is two, which is the index of the last element. And then we access its ID and increase it by one, which is four, simple as that. Next, we have task filled, and we pass value as to do which we get from request dot body, and for accessing task ad dot task. Next, we have text, and we pass value todo dot text. Last, we have status, which is what? We to do dot status. Now I think this might confuse you. We define this Nut object separately. C Nu todo equals to past this here. And in the push method, we simply add this new to do. I think this looks more clear. Also, one thing I want to tell you in any API at the end of the callback function, we must at response dot sg. Otherwise, on our front end, our request keeps running, and that's make our overall speed down. So make sure in every API, we return something. You might ask, what should we return from the post request? From the post request, we can return recently added data in our server at database. So our front end gets all the information like ID and use them as they want. So here we simply return this new to do, save the changes, and take a look, send the request again and see now we are getting data with ID four. If we fetch all to do from the Get request, C, we get four tu dos. So we successfully create post request and add new Tudo in our Tudos array. Let's quickly recap what we learned in this lesson. So we use post request for creating new data on the server, and we get that new data from the body of the post request sent by front end. For tasting that, we use this tender client extension and send our data in JCNFmat which is the common format for sending data. Now in the back end, we need to convert that data into simple Javascript format, and that's why we use Express D JCNMddleware and add it before our APIs. Without this Express dot JCNmddleware, we are getting request dot body as undefined. After that, we add the new data in separate object with it's all filled and then simply push it in the Tudou's array and at the end, return the new added data from response dot SN. Simple as that. Now in the next lesson, we will improve this post request. 35. Validating user Data: Currently, our front end is sending whatever data they want to send. But what if someone don't send the required data like Tas text or text array or status. Without them, we can't add incomplete data in our storage. It's bad for our application. So in that condition, we have to add data validation in our API. So at the beginning of our API, we will check front end is passing all the necessary data or not. If it is not passing proper data, then we stop the request immediately with proper error message. Let me show you what I means. Here, after we are getting the data from the request dot body, we add simple condition. If todo dot task is not available, then we return error from here. So in the Cali brackets, we write response dot send task is required. Now here is one thing. Even if we write here response dot send, our remaining code will also work. To stop running the code from here, we have to add here return. Without this return, our remaining code will anyway run. Don't forget to add return. Now let's duplicate this I block two more times using Sift plus alter plus down arrow or Sift plus option plus down arrow. Now we simply change the condition for text to do dot text, and change the error message. Texts are required. And at last, to do dot status, status is required. Also, here we can check more conditions like text should be array or task value should more than three characters, et cetera. For now, we don't want that complexity, so let's taste this implementation. Save the changes, open the post taste, and we simply remove this task fill. Send the request and see, here we are getting this message. Task is required. Beautiful. Now front end, just need to display this error message on the form or anywhere they want to display. By this way, we can manually validate our input fields data. But these are only three fills. Imagine we have seven to eight fields and for each field, we want to validate data. Then we have to write this if condition seven to eight times. Is there any other way to do that? Yes. Have special library for validating the user data. First one is joy. This is one of the most popular and robust data validation library in node JS, and we will also use joy for data validation in this course. Also, there are another library like yap and validator dot js. You can use any of this library. I personally like joy, and we will use joy in the next project. Currently, our main focus is on creating crowd APIs, which means create, read, update, delete APIs. 36. Passing status code: Now when we return an error from the server, it's better we also pass the error code with that error message. By that error or status code, our front end gets information about the success or failure of the SDDPRquest. You might already know about this, or you might seen this error. For example, when we don't found a web page, you know some website display 404 not found page. This 404 is the error or status code for not found. See most common error or status code for SDDPRquest. First one is 200, which means all o. This is the default status code which sent by our express application. In our request also, you can see here we are getting status 2000. Next, we have 201 code, which means created successfully. If we create a new data on our server, then we can return that data which status code 201. You tell in which HTTP method, we can return status code to 01, write? In the post request, if our data is successfully created. Next, we have status 400, which means better request done by front end. These include some missing or invalid or unauthorized access requests. And yes, for data validation, we will return error message with this 400 status code. Next, we have 404, which means not found. Suppose we are sending get request for getting the single to do with ID ten. Now, that is not available in our data. So at that time, we can send response with 404 status code. Another important status code is 500, which means internal server error. Suppose we get some error in creating the new to do on this server. Then at that time, we will return response with status code 500. Are many status code, but for now, these are most useful. Don't worry with practice, you will remember all those status code. Now, for passing the status code with our response, we can add here multiple cursor. So press Alt or Option and simply click where we want multiple cursor. And here we add dot status, and in this Status code, we want to pass for invalid data. We pass 400 and that's it. Press SCAP for remove multiple cursor and that we can pass data code with our request. Also, if we successfully create data, then we return response with Stas 201. Save the chan cheese and take a look. Send the request again and see, here we get error status code, 400 bad request. Lovely. 37. res.send & res.json: Till now, we are sending the response using response dot send method. But this response dot Sen method is used for general purpose, which means in this response dot SN method, we can send any type of content like plaintext, SDML or we can also pass JSON data. Now when we create API in node, most of the time we want to return data in the JSNFmat because it is much easier to handle. Here in the response, we have another method called response dot JSON. This will automatically converts our data in the JCNFmat and also it will set header content type to application slash JSON. Don't worry if you don't know about header content type, we will see that in the next section. We will use response dot send for simple responses, whether text, SDML or objects, and we will use response dot JSN when we want to ensure that the response is in JSN format and properly formatted for JSN clients. Both works almost the same. But for JSN data, response dot GSN is more convenient. In the first GAD request, we want to send a plain text. We use here response dot SN. After that, we want to send to do array, so we can use ar response dot JSN next, also, we want to send object, then what we will use. We use response dot JSN let's also remove this console. We don't need consoles in our server. It is just for testing. Next, here we are returning error. First, we change the send with JSN JSON, and JSN it's better we pass that error in object. Wrap this string in object and simply addhe message property and colon. Same we do for this error and also for this last error. And when we successfully creating a new to do, then we are returning the new to do object. So we also change the sand with JSON. Make sure you don't pass plain text in the response JN method. It will give you error. Save the changes, and in the previous testing, go to the header section. Here we get a bunch of details, but for now, we need this content type. See, it is set to text STML. Now let's send another invalid post request. See, here we get object which we send with message property, and now if we check our content type, see it is set to JSON. Use response dot send for plain text or DML and use response dot JSN for sending GSN data. 38. Update single Todo with PUT Request: Now let's create an API for updating our single todo. Suppose we want to update text of task or we want to update the status. So here we want to update little details about our current data, or we can also update all the information. So it's better we use here put request. Also, you can use your page method. It's totally fine. So app dot pot 0.2 slash Todos. Now here we need the todo ID which we want to update. We add here route parameter, calm ID. After that, we add callback function with request and response. Now, first of all, let's get the ID parameter. CsiD equals to request dot params ID. We know that this ID is string, so we wrap it with parse integer function. Our first task is we have to find which element of the array has this ID. And then by that element index, we can change other values very easily. So for finding the index, we use todos array dot find index method. Here, we get single to do object in this and then we pass condition T ID should equals to our ID parameter. This expression returns the index of the element, so we store it in variable called to do index. What if user pass ID, which is not available in our array? At the time, this todo index value will become minus one because this fine index method returns minus one if you don't found it to do index. Here we pass if condition to do index is equals to minus one. Then we return response dot status 404, which is not found and then dot Json and we send object with property message and simply return here message to do not found. Make sure you add here this return. Great. Suppose we found a todo index, then we have to update that element fields with our new data passed with API request. So at the top, first we get data from request dot body and store that object in todo variable. Now, instead of defining three different variables, we can use here object destructuring. At the place of variable name, we can simply add CLI brackets and write our property names which passed in the request dot body. First, we get task, then text and then status. And that's it. This single line of code works the same as these three lines of code. Now in the update, not every time we change task or we only change datas. We can change any of these three properties, and our front end should pass only those properties in the body of the request which they want to change. So here we can do something like this. If task is available, then we updated array to do index dot task is equal to task. So if this task is available in the body request, only then line will update the task property. Let's duplicate this I condition two more times. Let's replace this task with tags, tags, and tags. Also, this one status, status, here is the status, and that's it. Also, here we are missing one thing. Can you tell me, we have to return response at the end of this function. Response dot Json and here we send our updated to do object. Todos array in square packet, todo index. Save the changes, and let's taste this implementation. So go to Thunder Client and create a new request, write our endpoint, which is SDDP Local host, Column 3,000 Todos slash. Here we pass todo ID. Let's say one. Change this Get method to put method and let's pass data in the request body. Object with property task and value to this is the updated task. And simply send the request. See, here we're getting the updated data. And if we pass here ID ten and send the request, then we get here error message not found. You can see how simple it is to create a PI. So if you want to save your test, then press Control pluss or Command pluss then from here, we can also rename our test request Update todo. 39. Exercise Delete Specific Todo: Now it is time for interesting exercise. You have to create API for deleting the specific to do using its ID. This is a lot easy exercise. Exercise will help you to learn fast and also boost your confidence. Even if you can't complete the whole exercise, at least try to solve it because that's how you know on which part you have to work more. Give it a try and then what's the solution. So I hope you solve this exercise or at least try to solve it. Now let's quickly see the solution. So here we define a new API using app dot Tilt because we are deleting data here, endpoints to do slash Callan ID, callback request, response, and arrow function. First of all, we get ID from the route parameter. So Const ID equals to request dot params dot ID, and simply wrap it with parse integer function. This parse integer practice is very useful because when I'm learning node Jaz this one mistake I repeat a lot. Make sure you don't repeat this mistake. Here also, first, we have to find the index of the todo object, which has this ID. So from the Put method, we copy this variable line, and also we copy this condition for not found and piss them in our delete method. Now, after that, we have to simply remove that specific todo from our todos array. So for that, we use todos array dot splice method. In this, we have to pass two arguments. First, which index we want to remove, which is this to do index. Second argument is how many elements we want to remove from this index. Suppose we have index value two, and here we pass three. This splice method will remove three elements with the index two, and also it will remove the element with index three and four. In our case, we just want to remove this single element, we pass here one, and at the end, we simply return response dot Json and here we pass success message, object with message property and value two deleted successfully. Save the changes, and let's also taste this delete request. Create a new request, change the URL to STP, Column double forward slash local host, Column 3,000 slash Studo Let's delete the task with ID one. Select delete method. Here, we don't want to pass anything in our request body, send this request. See, here we get success message, which means our task one is removed from our to dos array. Now if we again send the request with the same ID, see, here we get not found. Y. You can see creating APIs is not that much difficult. And in this section, we created get, post, put, delete, all crud APIs. So I hope you understand how to use Express and create raised APIs with Express. Now in the next section, we will learn some advanced concepts of Express, see you in the next section. 40. Section 05 - Introduction of Middleware: Welcome to the fifth section of the ultimate NodeJS course. This section is all about advanced express and node concepts. We start with middleware, multiple types of middleware, how to work with different environment like development or production, template engines, and the professional fuller structure of node application. Let's start with middleware. What is middleware? In express, middleware is a function that either call the next middleware function or send a response to end the current request. In simple words, whichever function who call the next middleware function or send a response to end the request, that function is called as middleware. Now let me ask you one question. Think about this callback function which we pass here. Can we call this function as middleware? Yes, because this function is sending a response to end this Gad request. When our front end send requests to any API endpoint, that request pass through tunnel or pipeline in which all our middleware functions are placed in order. This pipeline is called as request processing pipeline. Suppose here we define middleware one, middleware two, and last middleware three will send response to end the request. Now when front end sends API request, first, this middleware one function will run. After that, that will pass our request to NST middleware two, and after completing the execution, middleware two will pass this request to middleware three, which will send the response. Our server will maintain this order. If we get error in middleware one, then other two middlewares will not run. Simple as that. Here are some common tasks for middleware. First one, it is used to log the request details. Also, it is used to check user who send the request is logged in or not. This is the most common and best use case of middleware. Don't worry, we will see that in the user authentication section. Now, last common task for middleware is passing the incoming data. We already done. Remember, this press dot JCN is a middleware function, which is passing the incoming data into JSON format and then pass our request to next middleware function, which is this main function. Now you might ask why we need these middlewares? Can we write all code in the single function? For that, imagine we are creating Bend for social media application. Have one API which is used to create a new post. Now we want to set condition for this request. Only log in users can create a new post. If user is not logged in, we will return an error, please log in with your account. Now we have another API which is used to add likes in the single post. In this API, we also want the same condition which is user must log in. Here, we have to again add that same code. Now instead of repeating this locked in verification code, we can define it in one middleware function and simply add that middleware for all the secured APIs. By this way, we don't need to repeat our code. A using middleware, we divide our code in small pieces, and that will make our code clean and more readable. Also, by middleware, we can stop unwanted users request to access the protected routes. To quick recap, middleware is a function that either called the next middleware function send a response to the current request. We can see middleware is very useful for any node application. So in the next lesson, we will see how to build middlewares. 41. Creating Custom Middleware: Now let's create our own custom middleware. It is really exciting and simple. So here in our application, we already added express dot Json Middleware using app dot U. Now, after that, we add another AbdTUuse method, and in that, we will add our middleware function. So this ABDTuse method is used to add middleware globally to our request processing pipeline. Now inside this use method, we pass callback function. This Colbec function has three parameters, request response, and next. Now you might ask, we know request and response. But what is the next parameter? This next parameter is used to call next middleware function. Now, inside this callback function, we write our logic. Let's say we want to console dot log our request methods and endpoints. In the template string, we add dollar C brackets, request dot method, dollar cbakets request dot URL. Now here is one thing. In every custom middlewares, which we define, at the last part, we have to call this next function. Otherwise, our request will stuck in this middleware and user don't get the response. Let me show you that practically. Save the changes and back to our tunder client. Let me open this request and send the request. Oh, sorry, I forgot to run this application using nodemon. Make sure your application is also running in the terminal. Nodemon index dot js, good. Now we send this request. See it is processing. And if we open our terminal, C, here we get the console of that request, which proves that our middleware function is called. So our current request processing pipeline is like this. First, we have expressed adjacent middleware, then we have custom middleware, and then we have the last middleware function which returns the response. When we don't call here next middleware function, our request we stuck here in this middleware and it shows us processing state, which makes our whole application slow. That's why always remember in every custom middleware, it's necessary to call next middleware function or we return the response. Here we call next middleware function, save the changes and take a look. Now, if we again send the request, see, here we get the response and in the console, we also get the request log. That's how simple to define our custom middleware function. I know this is very basic middleware function, but in the future, we will create custom middleware which checks our user is logged in or not. Also, when we define our middleware using app dot use method, that middleware will apply for all API calls, just like this express dot json middleware. 42. Built in Middleware: Express, we have very few built in middlewares. We already use one of the built in middleware which is express dot JSON. This middleware pass our request body data into JSN format. Without using this middleware, we can't get data into request Dot body. Do you remember we got nothing in request Dot body. Now another useful built in middleware is URL encoded. This is the similar built in middleware like express dot JSON. Express dot JSN Middleware used to pass JSNdata and press dot URL encoded middleware used to pass URL encoded data. This URL encoded data format is usually used when data is sent through simple SML forms using the post method. In simple words, these both middlewares are used to extract data from the request. WheneRquest has JCNData, then Express use JCN Middleware and when our request has data in URL encoded format, then Express use this URL encoded middleware. Middleware functions simplify the process of accessing request data, so we don't need to manually parse it simple as that. Now let's see how to add URL encoded middleware in our application. It is really simple. We add here app.us and inside this, we call Express dot URL encoded function. Save the changes and let's see this middleware is working or not. We go to the post request. Previously, we are sending data using this JSON format. Now here we have another option which is form encoded. Here we pass data in key value pair like task and here we add our text. This is new encoded task. After that, we want to pass text, which is array and in that we pass SDML and CSS. And at last, we want to pass status, which is to do. Now let's simply send this request. See, here we get new data created with status 201, our URL encoded is working. But wait a minute. Here we get this weird syntax of this array. Actually, it is not array. Our server store this array as string. See, it is coded in double codes, which means it is string. Why this happen. When we want to pass array or object in form encoded format, we have to add additional setting in our middleware. Here in the URL encoded middleware, add object with single property extended to true. Save this. And in the post request, instead of pass this array in single field, we have to pass it in different fills. Like our array name is tags, so we write tags, and here we add square brackets, which indicate it is an array, and then we pass values in multiple fills. First we write DML. After that, we add another key value pair, again, tags, square packet, and we write another value CSS. At last, we pass tags, square packet, and JavaScript. Now you understand why developers stop using this form encoded format. JSNFmat is much easier to pass and taste. See, now we get our text array. Also, let's see if we remove extended property from the middleware still it is working or not. I just want to see. Oh, it is not working. See, here we are getting texts are required, which means we are not getting texts. In previous node versions, this might work. But as we are using her latest node version, it is not working, so it's better to make it extended to true, simple as that. You might have question which middleware should we add in our node JS project? Express dot JCN or Express URL encoded. In modern world, 90% developers are using JSNFmat for data. JSNMddleware is common. But if you don't know in which format, your front end will send request data, JSN or form encoded, then adding both middlewares is beneficial for you. 43. Sharing Static Files from Server: Let's see another built in middleware which is used to send static files from the server. If you don't know static files, then static files are simply assets which are front end needs like SDML files, CSS files, JavaScript files, text files, images, paws, PDF, et cetera. They are called static because our server doesn't modify or process those files before sending them to the client. Example, we have the logo of our company in the server. We will send that logo file to our front end and front end will display on website. Now you might think we have static file on server. How can we share it? Don't worry, it is really simple. Let me show you that. Here we use app dot ug. Now for sharing the static files from the server, we have to use another built in middleware called press dot static. Inside this function, we have to pass the folder name which we want to share. Most commonly, developers called it public. You can call it whatever you like, but public is a common convention. You might ask, we don't have this public folder in our project, so we have to create it called public. Make sure you write the same name as you give your folder, and also make sure that folder is available in root of the project, not into any other folder. Now for demo we will add here any type of file or image. So here I have this image. I download this and add it in my public folder. And let's rename this file as Fire Watch or anything you want to call it. Good. Now, as we set our public folder as static, we can access all files which are available inside this folder. So open a browser, and here we write our base URL, local host column 3,000 slash. And after that, we can write our file name which we want to access, firewach dot P. If your image file extension is PNG or JPG, then you have to write the same file extension. Here, I don't get the file. What is wrong? Oh, we forgot to save these changes. Now again, try to access this file. See, here we get our image. So we will add all our static files into public folder and we can access them directly here. Our front end will use this URL to show images, pawns, or anything. Also, in our application, we can define one or more than one static folder. Like some developers like to addhe Assets folder, so we can duplicate this middleware and simply replace folder name by assets. Just make sure that folder is available in the root. Now many developers like to add prefix for static file path. Currently we are accessing our static files directly after local host column 3,000. By adding prefix, it will look like this. Local host column 3,000, slash Static slash firewatcht web P, or local host column 3,000 OTRs firewatch web P, et cetera. Let me show you how we can do that. For that, we just addhee our prefix before our express static middleware. ATR if the changes if we refresh our page, see, we don't get here static file. We have to add Autar in the URL, and now we get our static files. That's how we can share static files from the server. Now let me give you a little exercise. Add one static file in the folder called assets and simply access that file in the browser with prefix profile. I know you can do that, so I'm not showing you the solution. It is really simple. 44. Useful Third party middleware: Let's see some useful third party middleware. We call them third party middleware because it is created by third party. First one is Morgan. This middleware is most popular third party middleware for logging the SDDPRquest. Now when I was learning node has, I have this question. Why developers wants to log the SDP request? What they will get from simply logging the SDP request? I know you have the same question. When we log SDP request using Morgan, we can keep tracking of which API is calling more time. Which API is taking more time to response, how many API calls get filled, debug the weak API, and many more benefits. Usually, by logging the SDP request, developers can monitor, debug and improve their APIs. Now let's see how we can log the SDP request using Morgan. Here is a Morgan package. C, it has a 4 million monthly downloads, which is insane. And as we know, we use this command for installing Morgan package. So simply copy this and stop our application with Control plus C and paste it in our terminal. Good. Now let's run again our application. Now, in our application, we created this custom log middleware. We don't need it, so we can comment out this code. Now to use Morgan, first, we have to import it in our application. So at the top, consed Morgan equals to require Morgan. And at the bottom, we add app dot U, and inside this, we call this Morgan function. Inside this Morgan function, we can pass predefined format of logging request. For example, we have Dev for development combined for more details, common, tiny, et cetera. If you want to see all the details, then you can check out this package page. Here, you get all information about formats. Now, in our code, we simply add here double codes. See, here we get suggestions. Combined, common Dov short, tiny for now, let's go for Dev Save the changes and take a look. Now hit any API in the terminal. C, here we get the request details. First, we get the SDDP method, then endpoint, then status, response time, and size of the response. By this data, we can improve our APIs. If we again send the request, see, we get new log. So that's how Morgan will help us. Now the next third party middleware is helmet. Is another popular middleware, and we all know what helmet do in our regular life. It protect our head from accidents, and that's what helmet middleware also do. It is an excellent option to enhance the security of our app with minimal configuration. And also, it is commonly used in production environment. Many node application use this middleware. So we search here helmet. Here we get this package. Let's install this package. Open terminal, stop the application, paste the command here. And if you want to install the same version as I'm using, then you can add here version as well and hit Enter. Hood. Let's run our application again. Now to use this package, first, we import it at the top. So Const helmet, equals two require helmet. And at the bottom, before our other middleware, we add app dot g and simply call here helmet Middleware. And that's it. This will automatically add secure headers which will secure our Express application. Also, I want to clear one thing. When we add middleware in our application, Express add them in the same order which we add in our code. For example, currently Express, add helmet middleware first in the request processing pipeline, then JSON, then URA encoded, then static, and then Morgan. The order is also important for middleware. 45. How to Code according Environment : Now let's see how we can code according to our application environment. For example, currently our application is in development process, and when we deploy our application, it will be in the production environment. Now, when our application is in development stage, only then we want to enable Morgan middleware for our application. So first of all, we need to know the current environment. And yes, we know that the same way we try to know port. So we can simply consult dot log process ENV, and here we access dollar Cully Brackets, progress dot env dot node underscore ENV. This node underscore ENV is the variable name, same as this port. Let's see what we get here. Save the changes, and here we get undefined. Why? Because initially our environment is not STS development. Now, in Express, we have another way to know the current environment, which is by using app dot gat. And inside this gut, we have to pass ENV for environment. This app dot gt ENV will return the same result as this process dot nw dot node underscore environment. But when we don't set up node underscore environment, at that time, this app dot gt ENV will by default return development, which is great, right? Let me show you. So console dot log app ENV. Dollar curly brackets, app dot Get ENV. Save the Gengs and see, here we get development. But still, our process dot ENV is undefined. Now we want to only add this Morgan middleware if we are in the development environment. So we can code like this. Here we add I condition, app dot Get ENV. You can also use process dot NV, but then you have to change condition according to that. Now equals to development. It is true, only then we add this middleware. We move these inside this If blog. Now to indicate, we add here another console dot log, Morgan added. Good. Save the genes, and in the terminal, see, here we get Morgan added. Now let's change our environment to production to see Morgan is adding or not. First of all, we stop our application from running. For setting the environment variable, we write, dollar ENV, column, node, underscore ENV equals to in codes, we pass production. If you're Mac or Linux user, then you have to write here export, space, node, underscore ENV is equal to production. Make sure you write the correct environment variable name and value. Hit Enter. Now let's run our application again nodemon index dot js. See, here we don't get Morgan added. That's how we change our application environment and code according to that. Let's again change the environment to development. So dollar ENV, colon node, underscore EN V is equal to development. Or for Mac or Linux, export, node, underscore ENV is equal to development. And if we check our application again, see, here we get Morgan added. 46. env file & dotenv package: Till now we are setting environment variables using dollar ENV or export command in the terminal. But there is another simple way to define those variables using dot ENV file. In this NV file, we can simply add our all environment variables like port is equal to 3,000 or node underscore ENV to development. Or we can also define here the URL of our database. And many developers use this approach to define variables instead of defining them in the terminal. This ENV file keeps our applications sensitive information like credentials out of our code, which is a good security practice. Now, this ENV file is a simple text file. Can we load its variable into our node application, so we can use them and code according to that. To use these environment variables in node application, we have package called dot ENV. Don't worry by just one line of code, we can use these environment variables. Let's install this package. NPM install dot ENV. Good. Now, in our index dot sile at the top, we have to just add one line require dot NV, and then here we call method dot config, and that's it. We don't need to do any other thing. And also, the good thing about this approach is we can access them same using process dot nw dot porD and process dot nw dot node underscore ENV. Let's run this application. Good. See, currently we are in the development environment, and that's why we get Morgan added. Now, to show you, I change the port to 8,000. Don't use the port 5,000 in MAG because it is already running in your system, and we change ENV to production. Save this, and now we have to manually restart our application because Norman only restart our application when files with these extensions will change. See, our port is changed to 8,000, but what is this? Our ENV is the same as before, which is development. But in the ENV file, we set it to the production. Can you guess? It is because in the last lesson, we hard coded our node underscore ENV value using dollar ENV or export keyword. So our application, remember those settings. So always remember when we have dot ENV file and we also set our environment variable using terminal, our node application gives more priority to the terminal value. To solve this issue, we can simply remove that node underscore ENV value. So write, remove it, path, ENV, colon, node, underscore ENV. Or if you are Mac or Linux user, then write unset, space, node, underscore ENV, and hit Enter. Now restart the application. See, here we get the production. And if in the ENV file, we change ENV to development, save the changes, restart our application using nod moon. See, here we get the development because we get Morgan added. 47. Different Settings for different ENV: Currently we are manually changing our environment variables because they are just two. But in the real world, we might have more than two environment variables. Like we have different database URL in the development and different URL in the production. Similarly, we might have secret key for authentication, et cetera. Now when we have these many environment variables, it's difficult to change the variables manually. Now, how can we solve this? To solve this problem, we can create two separate ENV files dot nw dot development and dot nw dot Production. You can even create dot nw dot Testing. In these both files, we will define our different environment variables. After that, in our index dot js, we can simply put condition if our node environment is development, then we load dot nw dot development file. And if our environment is tasting, then we load this dot NV dot tasting file. Simple as that. Let me show you this practically. Here we create a new file called dot nw dot Development. This file, we define various environment variables. First one is port is equal to 3,000. K is equal to do underscores secret. We can also add node underscore ENV is equal to development, and that's it. Now let's create one more file called dot nw dot production. And inside this, we add Pd is equal to 8,000 K is equal to pro qi and at last node and a square E and V is equal to production. Save this, and now in the index dot s, we just need to add condition. So at the top, here, we first create a variable called ENV file equals to, and here for using ternary operators, we pass condition if process dot nw dot node underscore NV is equal to production. If it is true, then our ENV file should dot nv dot production. We set dot nw dot development file as our environment file. Now, simply in this config method, we have to pass object with property path to ENV file. Very simple condition. And here to show another NV variable, here we use consol dot log, process dot nw dot. Let's check it is working or not. Currently, we are getting Morgan added. Now let's stop our application. Dollar ENV, colon, node, underscore ENV is equal to codes production. If you are Mac or Linux user, then you have to use export, node, underscore, EN V is equal to production. Now let's start our application. See, here we are in the production environment because Morgan is not added, and here we get Pro key and our port is also changed to 8,000 so that by using different ENV files, we can define different environment variables. 48. Template Engines in Node Application: Let's see template engine in node. This topic is a little old and not commonly used in the modern world. So let's just understand what is template engine. Basically, template engine is a tool that allows us to create dynamic SDML pages. So instead of manually writing STML for each page, we can create a template, and by using engine, we can automatically insert data into that template. Then send the generated SGML file to the client browser. Suppose we want to create an old style blog website where all blogs have the same layout, but only their content is different. Now we don't want to manually create an SGML file for every blog post. That would be time consuming and inefficient. Instead, we can use a template engine to create a single template for our blog layout, and the template engine will dynamically display the blog content based on the data we provide simple as that. There are many template engines in no Jaz, but most popular is PUG and another is EJS. This both works the same. Only their syntax is different. Let me show you about PUG. So in our terminal, we write NPM install PUGOr if you like to install same verson, then write at the red three dot zero dot three. Good. Now in our index dot JS file, we have to set the view engine, which is the template engine to PUG. So we write here app dot set. Here, we want to set engine, so we write view engine. And at the second parameter, we simply pass PUG. So this line we set PRG as our view or template engine. Now we have to create a template our SDML page in POG. So in our application, we create a folder called views. Make sure you write the same name as views. And inside these, we can create a file called template dot POG. You can take any file name. It really doesn't matter. Here, we have to write code in Perg syntax, which is very similar to our SDML. Here we start with HTML. Notice that here I'm not using angle brackets for tags. Inside of the SDML, we can have head, so we write it like this tree structure. Inside of the head, we can add title here we want to get value of title dynamically. We write our tag name equals, and here we write our variable name which we pass at the run time. Title. Don't worry, I will show you everything. Now, after the head, we know we can add body tag, so we move in same parallel line as head and addre body. In PRG, we don't have to close the tag. Now in the body, we can addre H one tag equals to heading and after that, we add paragraph equals to content. Simple template for blog. You can see this is very clean syntax than regular SDML. Many developers like it, but many doesn't like it. Save this file and let's see how we can render SDML page and pass these variables dynamically. Previously, we define an API for simple root route in which we simply return response dot Send. This is task track project. Now at the place of simple text, let's render our Perg template. Here at the place of response dot Send, we write response dot Render. And this function takes two arguments. First one is the file or template name which we want to render. In this case, it is template, and the second argument is the object with the variables and its value which we define in that template. So first of all, title to, let's say, blog one. After that, we have heading to template engine, and content to ease pug really good, I don't know. Save the changes, and in the browser, we go to local host Column 3,000. Connection error might we forgot to start application node one index dot js. Oh, currently it is in the production environment. Let's set it in development environment. So dollar ENV can node underscore ENV is equal to encodes development. Or if you are Mac or Linux user, then you can use export, node underscore ENV is equal to development. Make sure you don't pass here codes, and then we start the application. See, it is listening in 3,000 and if we refresh our page, see, here we get the Perg template. Title is blog one. Heading and content is also same as we pass. So that's how we can render an SDML file on the server and then send it to the client browser. I don't think modern companies are using this way because most of all companies use Rag, angular or view for front end. 49. Cleaning up the Code Application Structure: Currently, if we see our index dot JS file, it feels we really messed up our code. Everything looks very cluttered and not maintainable. So let's structure our node application, which is used in the real world. So currently, we added all to do related APIs in the single index dot JS file. Imagine in another e commerce application, we have another set of API for users. We have another set of APIs for card related features. At the time, we can't add all those APIs in the same index dot js file. The solution is we can create a separate folder called routes, and in that, we will add files for each set of APIs. We create a new folder called routes. This is common practice for application structure. Now here, we create a new file called todos dot js, in which we will define all API routes related to todos. First of all, let's cut all routes from the index dot JS file. And paste it in the todos dot js file. Now you might ask in the index dot js file at the top, we have app instance and using that, we define different API routes. But here, in the todos dot JS file, we don't have that app instance. So how can we define routes here? You might say we can recreate the app instance, but that is not possible. It will not work. So in the express, we have another instance called router by which we can define API and points just like we are APIs using app instance. Here, we first input express const Express is equal to require Express. Now in this express, we have another method called Router, which will return the router instance, and that's why we store it in variable called router. Now, let's simply replace this app instance by this router instance. So select this app and press Control plus D or Command plus D, which will select all app instance and replace it with router. Good. Now we have defined our routes in the different file. But how our index dot js file will know, these routes we want to add in our application. For that, we have to export this router instance from this file and we add it in the index dot js file. Simple as that. So do you remember how can we export variables from the node file? Right, we use module dot exports is equal to router. Save this file, and in the index dot js file, let's remove these blocks. We don't need them, and we add here app dot g for adding those routes in our application. Here at the first position, we add router prefix, same as this static file. Most of the time, developers like to add here slash API. After that, at the second argument, we pass our router instance from the todos dot js file. So at the top, we import that router using require function. And here we pass our file path, which is slash out todos. Now, as we know, this require function will return router instance, so we can store it in variable called todos routes. And at the bottom, here, we pass Tudous routes. And done. Also, I found we need this Tudous array in the Tudos file. So we cut it from here and paste it in our Tudous file. Save the changes, and let's check our application is working well or not. Remember, for all to do routes, we need to add prefix API before endpoints. Send the request. See, it is working. Now, one last change I want to do is in our TudsRoute, we can see we are adding Tudos before every route endpoint. So we can commonly pass that slash todos at the prefix in the index dogs file. Save these. Now in todos dot js file, we can remove slash todos from the endpoint. Also, we remove todos for all API endpoints. Save this and we are good to go. We can also remove these unwanted lines. We don't need them. See, now our index dot js file looks clean and more maintainable. We will follow this application structure for the rest of our course. So here our Section five is over. You can quickly see the summary PDF and recap the whole section in two to 3 minutes and I will see you in the next section. 50. Section 06 - Asynchronous vs Synchronous: Welcome to the six section of the ultimate not JS course. This is the repressor section for some AdvancEvAscript topics like synchronous versus asynchronous, callback function, callback hell promises, and async await. A lot of developers are confused in these topics, so it's better we understand it. So if you are already confused in these topics and you want to master node js, then in upcoming sections, you will face a lot of issues. It's better to learn these topics, which we can call as asynchronous JavaScript before we dive really deep into node applications. In all node applications, we use these topics a lot. Let's learn these topics. Are simple and easy to learn. Also, if you are already confident on these topics, then you can skip this section. It's totally up to you. Now before we start learning concepts of asynchronous JavaScript, let's understand difference between asynchronous and synchronous. It will help us to understand better. What is synchronous? Synchronous programming means our code run line by line. Each line must be completed before we move on the next line. In simple words, synchronous programming is like following a recipe step by step. Each step must be completed before moving on to the next one. If one step takes a long time, we have to wait until it's finished the execution, and then we can continue. For example, we are preparing a cake for birthday party. Now there are step by step process for let's say, first we mix ingredients, then we put it in oven for baking, and finally, we decorate the cake. Here, we have to follow the steps line by line. We can't directly start decorating the cake without baking. We have to go in step one, step two, and step three. That's the synchronous example. Synchronous code is also called as blocking code. Let me show you the blocking behavior or blocking code example in JavaScript. So to practice these topics, we create a new folder in the projects folder called asynchronous JavaScript and open this folder in the VS code. Now inside this folder, we create a simple JavaScript file called index dot js. Good. Now here we write three console lines. So console dot log. Step one, start. Another console dot log. Step two, and last, consol dot log. Step three, and let's run this code. So in terminal, we write node, index dogs. See, we are getting the output line by line. First, we get step one, then step two, and then step three. Now you might say, we can't see the blocking behavior of this code. How can we see that practically? Currently, we are getting this output without blocking because not a single line taking more time to execute, every line execute immediately. Let's add little block in this code. Here, after Console one, we create a function called fetch data. In this function, we will pretend we are fetching data from the database. As we might know, fetching data from the database can take time like two to 3 seconds or more than that. For now, we just add some delay using empty four loop, which can take some time to execute. Here, let I is equal to zero, I less than one and nine times zero and I plus plus. Simply, we don't want to do anything in this fall loop, so open close curly brackets. Now, this line can take one or 2 seconds to execute and after that, we move our console step two up and right here, data fetched. Here before our step three, we call this fah data function. Can you guess what we get in the output? Let's see. Save the changes, and let's run this file. See, after step one, our code stop for a little bit for our function to execute. Then after that, we get data fetched and then step three. Here, for a little, we can see blocking behavior of our JavaScript code, which is called as synchronous JavaScript code. Now you might guess what is asynchronous. In asynchronous also, our code runs line by line. But for moving forward, we don't need to wait to finish that task. We can start a task, and if it takes more time, then we can move to the next line. In simple words, asynchronous programming is like doing multiple things at once and not waiting for each line to finish execution before starting the next line. You can start a task, and while you wait for it to complete, you can do something else. For example, you are preparing a keg and also watching this course. So you put the cake in oven for baking, but this baking can take ten to 15 minutes time. So at that time, you can do other things instead of just waiting for cake to bake. So you start watching this course. And if you like this course, then at that time, you can share this course with your friends. Similarly, if we define our sum code using asynchronous JavaScript, if that line takes more time to execute, then our JavaScript code will not wait there. It will run forward in the code and when that line finish its execution, then it will run that line. We can do multiple things in asynchronous JavaScript without just waiting for one line to finish its task. This is the fundamental difference between synchronous and asynchronous JavaScript. By default, our JavaScript code is synchronous, but Javascript provides some methods by which we can make our code asynchronous for doing specific types of work. Also, as we know, node is popular because it can apply asynchronous nature. Now let me show you how we can make our synchronous or blocking code into asynchronous or non blocking code. Here at the place of this four loop which is keeping our code busy, can add another method for adding delay. We add set time out. This method takes two argument. First one is the function and second one is a delay time. For example, we pass here 10,000 milliseconds, which is 10 seconds. Now at the first place, we simply pass function and inside it, we move this step to data fetched console. After 10 seconds, this function will console data fest. Now, can you guess the output of this code? Let's see. See, first we get step one. After that, in the background or function is running, but that didn't stop our code there. Our code continue to run step three, and when those 10 seconds will end, we get step two data ft. So this is the non blocking or asynchronous code. Synchronous code, wait for one line to complete execution and asynchronous code, wait for that line in the background and continue to work forward. You might ask, what is the best synchronous or asynchronous. In my opinion, both are useful. No one is better. They both serve different purpose. Synchronous is great when we need task to execute in a specific order or when the task is quick and non blocking. Provides simplicity and predictability. We asynchronous is important for tasks that take time, such as file handling, database access, or network request, where we don't want to block the main thread of our server. In node application, we will use Asynchronous JavaScript we want to perform non blocking operations like making database queries, API calls, reading and writing files without freezing the main thread. Main thing is our application should work in non blocking manner, which will give our users fast and great experience. So as we know, by default, our JavaScript code is synchronous. But JavaScript provides some methods by which we can make our code asynchronous for doing specific types of things. First one is by using callback function. Another method is by using promises. In this section, we will learn deeply about these methods. 51. Callbacks in JavaScript: Now let's understand callback in JavaScript. So what is callback function? A callback function is a function that is passed as an argument to another function and is executed after a specific task is completed. Let me explain you callback using real world scenario. Suppose you are ordering sandwich from the sandwich shop with your phone, so you call the Sandwich Shop and give your order. They tell you it will take 20 minutes to prepare and deliver. So you hung up the call and do other things instead of just waiting for the sandwich. Now, when sandwich gets ready, the delivery person rings your doorbell and gives you that sandwich simple. So in this case, you call the sandwich shop and give your order is like starting an asynchronous task. After that, they tell you it will take 20 minutes. This is the delay in the asynchronous task. Then you hung up and do other things instead of just waiting for the sandwich. This is the non blocking behavior, which means our code continues to run forward. When Sandwich gets ready, which means our asynchronous task is completed, the delivery person rings your doorbell and give you that Sandwich. This is the callback function being executed when the asynchronous task is completed. So a callback function is passed as an argument to another function, and also it is executed after a specific task is completed. In simple words, whatever we want to do after the asynchronous task is completed, that we will pass in the callback function. Now if you're working or learning Javascript from the long time, then bet with me, you already used callback function in your code. Just you don't know that function is called a ColwcFunction. For example, do you remember in the set timeout function at the first position, we pass function which executed after some delay. And you are correct, this function which we passed as an argument is called a callback function. Same as we pass callback function in the set interval function. Let me give you another example. I almost all array methods, we pass callback functions. Like in forage method, map method, filter method. In all these methods, we pass callback function. Also, in our previous project, we pass callback function in the app dot get app dot post, app dot pot, delete, and in all methods. Remember, those are also called as callback functions. Now for basic understanding, let's create one function and pass it as callback function because in node, we need to pass callback function a lot. So let's remove this code. If you want to watch the previous code at the bottom of this lesson, you will get Resources folder Zip. Download it and unzip it. In the resources folder, you will get Gita links for all code section by section. So you can get reference from that. So first of all, we write console dot log. Start. Now we create here function called fetch student in which we will pretend we are fetching data from the database. So to simulate delay for data fetching, we add here again, set timeout function. And at the first position, what do we pass? Right, not just function, we pass callback function. So we are passing here function using arrow function syntax. Arrow function is another way to define function, and it is much cleaner for callback functions. Now at the second argument, we pass milliseconds, let's say 3,000. And here in the set timeout, we consult dot log fetching student data from the database. Now let's call this fetch student function here after the console line. To make it more realistic, we also pass here student ID, which is the ID of the student we want to fetch. Let's say one. Now when we complete the data fetching, after 3 seconds, we want to return that student data. So we return student object with ID. Here we get ID as the parameter and simply pass that same ID here. Also our student has name to Harley, and let's say we want its enrollment number, suppose 500. We are pretending we are getting this student object from the database. Now when we call this function, here we get the student data, so we can simply store it in the variable called student. To verify, we simply const dot log, student and pass here this student. At the end, we simply consul dot log, and now, can you guess what we will get in the output? Will we get the student data or not? Let's see. Node index dot js. See, here we get start, student undefined, and then we are getting fetching data from the database. Let me explain to you why. When we call this well stud function with ID one, first of all, the set timeout runs, which will execute this piece of code after 3 seconds. Now, at the time, we don't get anything from the function. That's why it stood undefined value in the student variable. Our JavaScript code continued to run. This is why we get student to undefine then and then after 3 seconds, the set timeout function will console this fetching data line. Now the thing is, how can we run this code and get the student data? What is the solution here? To solve this, we use callback function and we will do that in the next lesson. 52. Solving Problem using Callback: So in the previous lesson, we get the error undefined student. Now, let's solve this problem using callback function. First of all, we don't need to store the result in the student variable. Now, to solve this issue, we will do little change in the Fed student function. So after the ID, we pass her callback function as parameter. And at the place of return the student object from the function, we will call this function or call back this function and simply pass student object in it. I know it is a little bit confusing. See this lesson and you will understand callbacks very well. Now, as we are accessing callback function as parameter, we have to pass that function as second argument when we are calling fair student function. So here we pass function, and inside this function, we can simply move this console student. Now from where we get this student object. Right, here we get the student object in parameter because when we are calling this callback function in the fast student function, we are passing student object here, and that student object, we directly access here in this callback parameter. Let's see this is working or not. So node index dot Js. See, first we get start and then after 3 seconds, we get fetching data from the database and then using callback function print this student object, and that's exactly what we want. Here is our previous and current code. At the place of returning the data from the fat student function, we call another function for console dot log, the student data. This console line will only run when this callback function will call. By this callback function technique, we make our code asynchronous or non blocking. Now to make this clear at the place of this function, we use arrow function syntax. We remove the function keyword and between the parenthesis and GLY brackets, we add arrow. See, now our code looks simple and this way is very useful in node because as you notice, we always pass callback function like this. Instead of declaring it separately, we directly define here. You can see by using callback function method, we can handle asynchronous task. Previously, we use this Colbec notation for defining API routes. So that is the callback function. Callback function is just a name of the function which we pass as an argument into another function, and it is executed after completing task, specifically asynchronous task. Simple as that. Now let's add little difficulty in this. Suppose from this student enrollment number, we want to fetch his result details. After this fetch student function, we create a new function called Get result. Parameter, we add enrollment number because using that, we will fetch result from the database. Now, inside this function, we simply return object with properties, result ID to enrollment number, which we get in the parameter, and after that, percentage to, let's say, 70. Now as we know, we are again fetching the result from the database, which means it will again take time, and that's why this function is a singer on us. So to simulate delay, here we add set timeout function and inside it callback function, and again, wait for 3,000 milliseconds. Now, in this set timeout function, we move this return, and as we know this return has no meaning. We have to pass this result into callback function. As we did here. So callback function and simply wrap this result object with Callback function parenthesis. Also, before that, we can consult dot log fetching result from the database. Good. Now, where we call this Gad result function, think about it. Yes, we can call Gad result function in this callback function because we get enrollment in the student object, and also we can call it here in the fetch student function. But as that function is all about fetching the data, and that's why we don't want to mix things. So we call the Ga result function in the callback function. The first argument, we pass enrollment number, which is student dot E undersceNum. And what we pass at the second argument, we will pass callback function here. Now, here in the parameter, we get the result object which we pass here, and we simply console dot log result to result. Also, we have to get this callback from the parameter. Save the gangs and let's run this score. Here, first we get the student data, and then after 3 seconds, we get result of that student. So let me quickly show you what is happening here. So first of all, the start console works, and then we call this fall student function. But because of this set timeout function, it will not run immediately. So our code move forward and simply console this end. Now, after 3 seconds, the set timeout will run the code which is available inside eight. So we call Callback function and simply pass Object. From where we get this callback function. Right, we get it from the parameter, and where we define that callback function, it is here in the fat student function, and that's why we get student details first. Now, after we get the student details, we call another function, which is G result. So this G result function will run, and because of set timeout, it again takes 3 seconds to execute. And inside this, we call another callback function, and where we define that callback function, yes, here, and at last, that callback function console this result, and this is what happening here. If without callback function, we want to run our code in same order, then we can do that. We get undefined student and because of that, we can't even get result. So now you understand why I put so much weight on the callback function. Because if you get confused in callback function, how can you focus on learning node? 53. Callback Hell: Currently in this code, we add this callback function inside another callback function. Now imagine if we have another asynchronous task, let's say update result. Inside this, we pass result dot result ID, and Callback function will run after our result gets updated. We get here updated result. You can see our code looks messy and hard to read because here we have many nested callback functions inside each other. Let me remove these all consoles so we can see clearly see, here we get nested callbacks. This situation is called as callback hell, where we have many nested callback functions inside each other and that makes the code hard to read and manage. If we have the same code in synchronous, then it looks like this. First, we call fair student function and store its data in student variable. Same as we call Get result function and pass enrollment number of that student. At last, we call updated student function and pass result ID, which we want to update. You can see synchronous code is very simple and easy to read and manage. Now you might ask, what is the issue with the callback hell? See, even if we have callback, our code will work. The issue is only it is hard to read and manage because in the real world, we might have more than three nested callbacks. Then at a time, it will be really hard to read, manage, and even scale. So we need to make our code easy to read. It is really simple. Just we have to make our anonymous function, which is the function which don't have name. Convert these anonymous callback functions into named functions. In simple words, at the place of defining this callback function here, we will separately define them and pass that function name here. Let's add our consoles back good and remove this last function. We just added it for demo callback. Here we create a function called cost, print student. We can call it anything, and I am using here arrow functions in text because it's easy for callback function. Now we can cut this Callback function from here and paste it at the place of this arrow function. Good and at the place of that callback function, we simply pass print student function. Make sure you don't call the print student function here. We just have to pass the function as parameter, and this print student function will run here as the callback function. Now, let's quickly convert this anonymous callback function in named function. So Cons print result is equal to, and here we simply paste this callback function. And at the place of this, we pass print result. See, now our code looks clean and easy to maintain. To quick recap, when we have nested callback functions, we get callback heal issue, which is hard to read and manage. What is the solution? Right, we convert our anonymous callback functions into named functions. Simple as that. 54. Promise in JavaScript: In the previous lesson, we see how to handle asynchronous task using callback functions. But in that implementation, we get this callback hel problem, and also we solve that problem with named function. Now my question is, how many new functions we create? Imagine we have ten nested callback functions, then we have to create ten named functions before we call our main function. Is there any other way to handle asynchronous task? Yes, there is another way which is by using promise. What is promise? A promise is a special object which is able to hold result of an asynchronous operation. In other words, promise is promise to give you the result of the asynchronous operation, or if asynchronous operation fails, then it will return error. For now we learn promises in the new file called promises dot js. And then we update our previous code with Promises implementation. So first, we create promise, and then we will see how to consume that promise. It is really simple. So to create promise, we write new keyword and then promise. Now, this promise is a class and it takes an argument which is function with two parameters. So here, first parameter is resolve and second parameter is reject and arrow function. Now inside this function, we can perform our asynchronous task. So here, again, we are assuming we are getting data from the database. So we write here, set timeout function and pass callback function and 3,000 milliseconds. Now imagine here we get our data from the database. So we create one variable called student equals to object, let's say, ID to one and name to Hurley. Now here we call resolve because we successfully get the data and we pass here this student. Here, our promise is ready. Now let's do this promise invariable called PR for promise. Good. Now let's see how we can consume this promise. It is really simple we write PR, which is this promise, dot, and here we have two main methods, then and catch. So when we create promise, it is by default in pending state. And if we complete the asynchronous task, then promise is in resolved or fulfilled state. And if there is an error, then promise in rejected state. This is called a life cycle of promise. Here, our promise is fulfilled because we call here resolve function. So when promise is fulfilled, then we get our data this then method. Now we store our data in this result parameter and then simply consult dot log this result. So this let's run this file. Node promises dot gs, see, after 3 seconds, we get this result. Now imagine here for some reason, we don't get data from the database. Here we create one variable called status, and make it false. Here we add condition. If status and my system automatically shut down, let me start it again. Yeah, I am back, so let's continue. I status is true, then we run this resolve function, else we simply call here reject function. Now for better practice, every time we want to return error, we create new error and pass our error message here. This is error message. Save the changes, and let's run these promises dot js file. See, we get this error here. Now let's consume this error, same as we get here data in the then method. After this then method, we add another method called cache and inside this also, we pass callback function. Here we get error in parameter and consult dot log this error. Save this and let's run this file again. See, we get that error here, and that's how we can consume promise using then and catch method. We can see instead of using callback function for doing something after asynchronous task, we can use promise for perform that asynchronous task and then simply consume that promise. In short, if our promise get resolved, then this then method will run, and if our promise get rejected, then this cache method will run, simple as that. If you are worried about the promise creation, then don't worry with practice, you will get comfortable with it. Let me tell you one thing. In real world, 99% time, we only consume promises. Only a few times we need to create a promise. Now in the next lesson, we will handle our callback heal code using promises. It will be fun. 55. Replacing Callbacks with Promises: Let's handle our Callback L code using promises. You can download code of Callback hel from below of this lesson. This code we write in the lesson four. Copy the code and paste it in another callbacltjs file or also in the resources folder and inside asynchronous folder, you will get this file as callback hl dot js. You can also add that in your project. Now, as we know, in promise, we define our asynchronous task. And here we have the two asynchronous task in two separate functions. Now instead of removing these functions, we can simply return a new promise from this function. Don't get confused. Let me show you what I mean. So here, in the felt student function, we simply return here a new promise. Now, what we pass in this promise, we pass here function, which has two parameters, resolve and reject. Now in this function, what we do right, we perform here a synchronous task. So we move this set time out function here using holding alter or option and aro chies. Now here we don't need this callback. At the place of callback, we pass our data in the resolve function, and also we don't need callback in the parameter. Now let's do the same in this Gad result function. So we return promise, and we pass here function with two parameters, resolve and reject. If you don't want to write this whole line, then let me show you shortcut for that. So here we write new promise without space, and select this suggestion. See, here we get our new promise. I don't show this previously because I want you get comfortable with promises. Now let's move this asynchronous code also in the function and at the place of callba, we return that data in resolve method and from the top, remove this callbag. Now let's consume this promise. At the top, we comment out this previous code in which we experience callback hell. Now here, first we call fair student function and passie ID one. This expression will return this promise. Let's store that promise in variable called PR. Here we have our promise in this PR variable. Now we just have to consume this promise. Part. Which method we use here, we use dot then method. Here we pass function. Here, we get parameter, data, or we can call it student anything, arrow function, and what we want to do if we have student data. We simply wants to call Get result function and pass here student dot Enrollment because here we have enrollment property. Make sure you write the same property as you have and done. So that's how we consume first promise. Also, instead of storing this promise in variable, here we can directly write this expression. You get confused in this, then don't worry, you can store promise in variable and then consume it. This is the common practice, and that's why I show you here. Now, as we know this gat result function will also return promise. How can we consume this promise? It is really simple. The place of writing ten method here, we can write it after our first ten method. Now what we get from this promise, result, arrow function, and simply console dot log result to this result. Save the changes, and let's run our Callback Hel file. Node callback hell dot gs. Good. See, first, it will fetch student data. After that, we fetch result and then print result. So we can see using these promises, our code looks more clean and easy to read. Now, if we have another function in callbaL then similar to this, we return here, that new function and call it. Now when we call that function and return it, we can add here another than method, simple as that. Some students might get confused about this get result function calling. They ask what is happening here? Explain this code in details. So here, I again, call this fetch student function and simply pass here and consume that promise using then method. And here we get student data. When we get student data, we can pass normal arrow function with C brackets. Now inside these CL brackets we don't have any code. Just we want to return Get result function with student dot enrollment. So because we just want to return this one line, we can remove these C brackets and we can also remove return keyword. This is the short way to return something from the arrow function. So when we want to return one line from the arrow function, then we write directly after arrow. Here we are returning this function. This whole expression is returning a new promise. So we can store it in new variable called new PR. Now let's consume this promise also. We write newpar dot the and then we get result, arrow function, and simply console dot log, result and print here this result. Now, at the place of this new PR, can we write this whole expression? Sure. At the place of new PR, we paste this expression. And that's what we did here. Now, as a best practice, when we have promise that promise can also return error using reject method. So it's better to handle that error. For that, we have another method, which is cache. We also see this in the previous lesson. So here we also add cache method. Here we get error object and we simply Consolatog this error. Now for testing, we simply add reject in gat result function before resolve method, and pass here new error, and error message, result not found. Save the changes and take a look. Let's run this application again. It is patching data. See, here we get result not found. If we get error in any of these promises, this sketch method will run. Simple as that. Let me comment out this reject method. It is just for testing. I hope your all doubts are clear. Now in the next lesson, we will see another easiest way to write this same code. 56. Async:await in JavaScript: Now as we can see in the Calbecl after this get result function, we are consuming another promise. Now imagine in this Colbecl after this get result function, we are consuming another promise. For that, we have to add another than method, and that also can be a little confusing. Let's make this code more simpler using async and await. What is async awight? Async awight is a way to write asynchronous code as synchronous code. By using async awight, we can consume promises in much easier way. So first of all, we call here fair student function and simply pass here ID one. Now, this function will return a promise which is initially in the pending state because in that promise, we are performing asynchronous task. So we can wait here for that promise to resolve using Awight keyword. So awight pauses the execution of the code until the promise resolved. Once the promise is resolved, it returns the data. Now when we get data, we can store that in variable const student. Now we have student object, so we can call Get result and pass here student dot Enrollment. This function will also return promise, so we again adhere Await keyword for that promise, get resolve and this will also return data. Const result. After that, we simply write CLO Parkansa log with property name, result, and press Ascap. Now you can see using a weight keyword, we can write asynchronous code looks like synchronous code. Let me comment out this previous code. Save this, and let's run this code again. Node, callbhll dots. See, here we get start fetching data from the database, and then we get result, and at the end, we get. So our code is working as synchronous because our code is blocking here this end. Now as a best practice and to make this code asynchronous, we have to always use this await inside async function because in normal function, it will not work. So here we create a function called print result. And simply move this code inside this function. Now you might ask this is the simple function, but a weight is only valid in ASN function. So how can we make our simple function as acing function? It is really simple. Just we have to add ASN keyword before function. And after that, we simply call this function print result. Otherwise, how it will work. Do the changes, and let's check this. Run again our file. Good. It is fetching and see here we get result and also it is not blocking this end. We can see by using async and await, we can write our asynchronous code looks like synchronous code. This is more readable and clear than this previous code. Now, what if this promise written error using reject method? Here we remove comment from the reject method. Let's see how we can handle errors in the async at method. So for handling error in asyncawt we need to use try and catch method. It is also simple. Let me show you. So first of all, we add try and in the Gy brackets, we move our code. Now if something goes wrong in this triplog our code directly move to the cache block. So we add here cache block, and this cache block has one parameter called error. And yes, it is the same error which promise written in the reject function. In the CLI bracket, we can simply consult dot log this error. Now let's see it is working or not. Save this and let's run this file one more time. See, here we get error. So in simple terms, if any error occur in this triplog then this catch block will run. Now, some students might ask. This seems like this 08 is blocking our code from running forward. And yes, it is true, but that is true only for this as function. Here we have console and after this function call. So in the output, we get start, then our function will call. In that function, first, it will call fair student function, which returns promise. So a weight will pause the execution of the code until the promise resolve. So our code will not move forward only in this function, but it will move forward outside of the function. And that's why after start, we get N. Then if we have other lines, then it will also run them. Don't worry, Asyncawd is a way to write asynchronous code looks like synchronous code, but our code will work in asynchronous way. To quick recap, when we have promise, we can use a weigh keyword. A weight pauses execution until a promise is resolved and we can only use a weight in the async function. For error handling in a syncowt method, we will use try and catch blog. We get any error in the dry blog, then our cache method will run simple as that. That's how we can consume promises in much easier way than this T and catch method. It's your choice, what you want to use. They both works the same. It's totally up to you what you want to use. Also, if in Async and AD you want to add tryCatch blog, then simply write Tricach and select this suggestion. See, here we get Tri case block. I hope you learn a lot from this section or these concepts get refreshed. Without clearing these concepts, we can't jump on the BG applications. If you are continuously watching this course, then take five to 10 minutes break, get some fresh air, and I will see you in the next section. 57. Section 07 MongoDB Basics: Welcome to the seventh section of the ultimate no JS course. Till now in our projects, we are defining data in simple JavaScript array. But the problem with this approach is when we restart our server or application, our data gets reset to defined value and we lost our changes in our data. Now, at that time, database comes in the picture, so we will store our data in the database. There are many types of database options like MySQL, SQL lite, Mongo Dib, et cetera. Mongo DB is most used database with node applications, and that's what we are going to learn in this course. Now, one thing I want to clear is after completing this course, you will not completely master Mongo DB because Mongo Di B itself is a four to 5 hours course, but I will try to cover as many topics as possible. So in this section, we will start with very basics of database, and then we move forward for creating, reading, updating, and deleting the data with exercise. I'm very excited, and I hope you are too. So let's dive into this section. 58. Introduction of Database: Now before we start learning Mongo Deb, it's better we learn some basic terms of database. So as you might know, database is an organized collection of structured information called data, and it is stored in the computer or on Cloud. In old schools, our teacher used a book or register to keep track of student attendance. That is database, but it is on hard paper. In today's world, we use computer system to store that data, so we can access it anytime and from anywhere. We all know this, right? Now, there are two types of database. First one is SQL database or relational database, and second one is no SQL database or non relational database. They differ in how they organize, store and manage data. Let me explain to you this one by one. So SQL stands for structured query language. SQL database is well organized filling cabinets. These two data in tables using multiple columns and rows like this. We can see this is very organized structure. Every column of the table represent different fill of data, like name, email address, phone number, and password, and every row of the table is a new set of user. We have to pass single user data for all these columns, and that's why it is organized table. Now, on the other side, no SQL database is like flexible board where we can organize data however we want. In no SQL databases, we don't have tables because they don't follow strict table based structure or schema based structure. SQL databases store data in more flexible formats like DSN documents or key value pairs. For example, if we have the same user data, we can store it like this in key value pair. We don't need to provide all fields for each user, and that's why we can call it schemas or schema flexible structure. Popular options for SQL is MesquLEqtOracle, et cetera. Where in the NoSQL, we have Mongo DiBRds et cetera. Might ask when we choose SQL and when we go for no SQL database. So it depends on which type of data you are dealing with and what your application need. We use SQL, if we want our data structured and organized in table. Also, if we need to run complex queries for analytics or if data consistency is used, then we use SQL database. On the other side, we use no SQL, if we want our data is unstructured or semi structured, except rapid data growth, we need flexibility in our data model our application is real time or big data, then we use no SQUL database. For example, we are creating e commerce applications, which has many features like user can upload reviews, product suggestion in which our data is unstructured or semi structured, and also users might give reviews in large numbers. At the time, which database should we pick? Right, we use here, no SQL database. Let's take one more example. Suppose we are building banking system where we need strict data and accurate financial transactions. Which database we should choose? Right, use here SQL. So it really depends on which type of data we are dealing with and what kind of application we want to build. Most of the time, your team will tell you which database you should add in your application. So don't worry about that. Many developers really don't know the difference between SQL and no SQL. You know, right? In many node applications, developers default choice is Mongo DB, which is the no Squal database. And if you want to become MSTech developer, this is for Mongo DB. In this course, I add MongoDB as database. Don't worry, we will learn MongoDB step by step. 59. Install MongoDB in Windows: Let's install Mongo DV on Windows, and if you have MG, then you can skip this lesson. First of all, head over to mongodib.com. Now go to these products and select Community Edition. Go for download Community. Scroll down. And here we can select Mongo Di B version. In my recommendation, please don't change it. Next, we can select our platform, and then you can select package. Don't worry about this, click on Download. See, download is started. Now, after completing the download, open that setup, and it will ask for installation permission. Allow it. Click on next. Accept the agreement. Click on complete. After that, from here, we can change our installation path. But if you don't have any reason, then don't change it. Just click on next. Make sure to select this Mongo DB compass, which is the application for MongoDB, in which you can view all database tables and edit or delete them. Click on next and install. This will take some time around five to 10 minutes because we are also installing Mongo DB compass. Now, after completing this installation, let's verify this. Open Command prompt, and write Mongo D and hit Enter. We get this error, Mongo D is not recognized as an internal or external command. So to solve this error, we have to again go to the Mongo Db website and here at the top products and go to view all products in tools. Now, scroll down on this page, and here we get the cell option. So select these now click on Download, scroll down. And here we again download this setup. Now, after completing the download, open that download folder and extract that zip which we just download. Good. Now, open that folder, and in the bin folder, we get this Mongos file. So just copy these and open your C drive program files. MongoDB server, 8.0 B, and here we paste set application. This Mongos is our Mongo DB cell. Now we have to do one last step, which is set this path to environment path. So copy this path in start, search for environment variable and open the edit the system environment variables. Let me close as things. Now, click on these environment variables, and in system variables, select path, and click on Edit. Now we have to add that bin path here, so click on New and pace that path. Click on Okay. Okay, and Okay. Now again, open Command prompt. We write mangoes and hit Enter. We will get the Mongo DB cell, so we successfully install Mongo DB in our system. Now let me give you a quick tour of this Mongo DB compass. When we open this compass first time, we have to enter our connection string, which is our local host, Column 27017. You can write this connection string, which I added and click on Save and connect. See, here we can see our database and also we can see tables and A we can see documents. 60. Connect MongoDB with Node App: So we install Mongo Di B in our system. Now let's connect that Mongo Di B with node application. So for learning Mongo Di B, we will create a new project because I don't want you to get confused with previous tastak project. We will add Mongo Di B as exercise in that project. It will be fun. So for now, in the projects folder, we create a new folder, let's say Mongo demo, weird name, but it is okay for learning. Let's open this folder in the VS code. Now to initialize this project, we open our terminal and write NPM in it I. Good. And here we create a new file, index dot gs. Now in node applications for managing and working with MongoDB, we will use one very popular library, which is mangos. In simple words, by using Mongoose library, we can easily work with Mongo DB. Let's install this library using NPM install Mongoose, if you want to get the same result as I am getting in this course, then right here at the rate 8.13 0.2. Good. Now to use this library, first, we import it using required function. Here we pass mongoose and we store it in variable const mongoos. Now, this mongoose object has many methods. One of them is connect, so mongoos dot Connect. Here we have to pass the URL of Mongo DB database which we want to connect. We open here, MongoDB compass application. Here we can see we have connection string, which is local host, column 27017. In our code, we write in codes, Mongo DB, column, double forward slash, local host, Column 27017, which represent the local Mongo Deb database, forward slash, and here we write our specific database collection name, let's say Mongo Demo this is not the application name, this is the database name. Don't worry, we will see this in upcoming sections. Now, this expression returns a promise, and you remember, how can we handle promise? We can use then and catch method, or we can use async await. Currently, we don't have nested promises, so to simplify, we can use here, then method. If you want to use ASN and Aviate, then you have to create a new ASN function. So here we add that ten method, which means we connect it successfully arrow function, and we simply console dot log, Mongo Dib connected successfully. So it might happen something goes wrong like Internet connection got lost, or database don't found or some type of mistakes in the connection string. At that time, we will get error in this promise. So we also add here catch method, and here we get error object. And we simply console dot log, Mongo DB connection failed. Coma that error object. So basically, we are saying to Mongoose, connect our application to this local database, Mongo demo. Now you might ask, we don't created this Mongo demo database. How can Mongoose connect our application to that database? Will it give us error? And the answer no it will not give us error because if that database Mongo demo is not available in our system, then Mongoose will create a new database called Mongo demo, and if that database is already available, then it will simply use that. Now, if this database connected successfully, then we log success message, and if our connection fails, then we log this error. Save the changes, and let's run our application using nodemon index dot JS. See, here we get connection successful. So that's how we connect Mongo Di Be with our node application using Mongos dot connect method. Now, let me tell you something. Previously, Mongo Di Be used to have an older way to connect with database, but it was not perfect, and developers was some issue with that. In some old code, you will see these options passed with connection. These options are just for handling the connection more better. You might use new URL parser to true, which tells Mongoose to use the modern way to connect with Mongo DB. Also, we get use unified topology to True, which tells Mongos to manage connections in a smoother and more stable way. Now in the new Mongo Di version, these options are by default on, so we don't need to pass them here. I told you about this, if you see this type of code, you don't get confused by that. Now in the next lesson, we will create our first document schema. 61. Importance of Schema: Before we store our data into our database, it's better to define litter structure for that data. For example, we want to register a new user on our website. So he fills form with name, email, phone number, and password. And when we hit register, we store these details in our database. Now, as a developer, we know sometimes user forgot to write name or forgot to write email or password. User can forgot anything. So to prevent these, we will define litter structure for that data, which means we can define name is required, email as unique field, which means every user should use unique email address. Phone number can be anything or user can also skip this information and password also required. Now if user don't pass name or write wrong email, then his data will not store in our database. We will return error for that user, and that's how we can prevent unwanted and unnecessary data being stored in our database. That's why defining structure is important and this structure is called a schema. You might ask in the database introduction lesson, I told you Mongo DB or no SQL is the schemas or schema flexible structure, and SQUL is the schema based structure, and now I'm telling you to define schema. Why? We know in MongoDB, we will store data in the key value pair. Suppose in our previous example, some user pass field name, email, as email address, or name as username, then how can we manage this type of data? MongoDB is schema flexible, which means we don't have to define schema. However, defining a schema provide consistency, validation, and predictability, which are crucial in most production level application. A schema help us to avoid unwanted or dirty data. Also, by defining schema, we can write query logic more clearly. Now you might ask Mongo Di B is schemas or schema flexible structure. How can we define structure in MongoDB? The answer is Mongo DB don't enforce schema its data. But by using other tools like Mongoose, we can define schema for our Mongo DB documents. Also, if you're familiar with SQL, in that we have table, suppose user, and in that table, we have rows for each user. Now in Mongo Di B that table is called a collection. That row can be called as document. Don't get confused when I use words like collection and document. They are very similar to table and row. To we recap, we can define schema for our Mongo Dew collection for better use of our application. Now in the next lesson, we will see how can we define schema for our Mongo Dew collection? 62. Defining Schema for Document: Let's see how we can define schema using mangos. So for that, we use new mangos dot schema, which is a class. Now in this parenthesis, we will add object with our fill name and structure for that fill. For example, first we need name, column, and here we write the type of data we want to store. So for name, we want to store stream. Make sure you write as in capital. Now after that, we might have email and this also we want in string. Now, as I told you before, we want to store email as unique value for every document or row. So how can we define that uniqueness here? Simply, at the place of this string, we pass object. This object has multiple properties. First, we want to define the type of this fill, which is string, and then we have another property which is unique and we set it to true. So if we have already email for one user, that same email cannot use for other user. After that, let's say we have phone and we pass here object, and we set type to number. Now here we don't want to make this fill necessary. User can also skip this phone filled. So here we don't pass anything. And if we only want to pass type property for the fill, we can directly write like this number. But I like to follow consistent syntax, so I leave this as it is. But in the name field at the place of this string, we simply add object with type to string, and also we want to make this field compulsory. We add here, required to true. Make sure here we write required, not require. I'm not sure only require is working or not. Also, we always store our EML ID in the lower case, and we can also define that here by lower case to true. You can see defining schema is not hard. It is very simple. Now, after that, we have password and we want to store it as string and it is the compulsory field. Tell me which properties we should add here. Right, we add here type to string and required to true. You are doing really great. Now, after that, this user might have hobbies, which can be multiple things. So we want to store it in array. Type to square brackets, which is array, and in that, we want simple string. So our hobbies might look like this array of string. Now after that, we might have is verified, which source user is verified or not, and we set its type to Bullion, which means true or false. And by default, we want to store user as unverified. So for that, we have another property called default. We pass default value as false. This is how we define schema for our Mongo DB collection. In the schema, we have multiple schema types like string, number, boolean, date, object, array, object ID, which we will see in the future, B for storing the binary data mixed for any type of data much more. If you want to know all schema types and its property, then you can visit this mongoose documentation. On this page, we get all the information. Now in the next lesson, we will see how to apply this schema for collection. 63. Creating Models: In the previous lesson, we created this user schema. Now, how can we define which collection should follow this schema? For that, we need to create a model. So first of all, we store this schema in variable called user schema. Now to apply this user schema, we need to create model. So we write here Mongoose dot Model. Inside this at the first position, we pass the singular name of our collection, which is here user. So this user will become users collection. If we want to create collection called post, which is plural, then here, we have to write singular name of that collection, which is post. Now at the second argument, we will pass our schema for this user collection, which is this user schema. Now this expression will return the model for user collection. So we store it in variable called user. Can you tell me why I'm using this pascal convention or why I use U for user model? It is because this user is a class and using this user class or model, we will do many things. To simplify model is like a blueprint for creating and working with documents in a Mongo Deb collection. Defines the shape of our data using a schema and provides a way to interact with that collection. In simple terms, the model allow us to create new documents based on the schema, read data from the collection, update existing documents, also, delete documents from the collection. In short, without model, we can't do anything with Mongo Di Bi collection. Don't worry we will see all these in the upcoming lessons. Currently, let me show you how can we create a new user using this user model. So for creating a new user, we write new user, and inside this, we will pass our user object. So the first field of this collection is name and pass value as code plus U. You can write your name. Next, we have email, let's say, code at did gmail.com. Currently, we are manually writing these values, but in the real world, our user from the front end will write this value and submit it using post request. And in the back end, we will handle that post request, and inside the post request logic, we will write this new model expression. So don't worry about that. Next, we have phone, which can be anything 23, 51, 552. Next, we have password. Make sure here we write the same fill name as we defined in the schema. Password to string 123, four, five, six, 78. And hobbies to array, and here I add learning, teaching, and tracking. For the last field, we already set the default value in our schema, so we don't need to pass that fill here. That's how we can create a new user or document of the collection. Here, we store it in a variable per new user. Now, currently, this new user is available only locally. In the next lesson, we will see how we can store this new user in our database. 64. Saving a new Data: So here we have new user data. Now let's store it in our database. So this new user data has one method, which is dot CV. By using this save method, we can store this new user data in our database. Now saving the data in the database is asynchronous task, which means it can take some time to save new data in the database. And that's why this expression returns a promise. You can adhere, await and when our data successfully stored in the database, it will return the stored user object from the database, so we can store it in variable called stored data and simply console dot log with stored data. Now as we know, when we want to use await, we need a acing function and only inside that function, we can use await. Otherwise, our code will block next lines. Here, before this new user object, we create a new acing function called create user. And inside this function, we can simply move this new user and save method. And at the end, we will call this create user function. Now don't save the file, it will automatically run this file. I terminal, I stop our node bond using Control plus C. Now save the changes, and let's see this is working or not. The terminal, we run this file using node index dot js. Don't use here nodemon because we only want to run this index dot js file one time. If we use nod M and we change something in our file, a new user will create every time. See, here we get new user data with our fills and at end we also get underscore ID, which is the unique ID for this document, and it is generated by Mongo DB and using this ID, we can do many things. Also, we get here underscore underscore to zero. Is that? This underscore underscore is used for document worsening in mangos. When we create a new document, Mongoose adds the underscore underscore filled and set it to zero. Now each time the particular document is updated, mangos increase the underscore underscore filled by one. For now, don't worry about that. Also, we can see this data in the Mongo DV compass application. See in the local database, here we don't get our database, click on the Tree dots and refresh database. See, now we get Mongo Demo database. Inside this, we have users collection, which we created using model, and in that collection, we have our first document with Unique ID, and also we have our fills. Let's say this Obs array, which is a key value pair, key is the index of that element, and value is our string. We get data from the database in our index dot JS file, then we get normal array of string. It is just showing here in the key value pair. Also, see, by default, we set this is verified value to false. And yes, we can change data from this application. So to quick recap, first, we create a new user object using this user model, and then we can simply use Lots method to save this document. Now let's try to store another user data because we need that data in upcoming lessons. I changed his name to Halley, email to Halley at direct gmail.com. If you want to change something, and you can change in the phone number, password, Harley 123, and hobbies, let's say, coding, Jimming and tracking. Save the changes and in our terminal, we run node index dot js. Good, see, here we get new data. If we check our Mongo Di B compass, we don't get here data. So we refresh from here and see here we get our new data. That's how is to data in our database. If we follow this step by step, then it is really simple. 65. Query the Data: Now let's see how we can query the data. But you might ask, what is the meaning of query? Query is simply a request for information from the database. In simple words, a query is just a way of asking the database for specific data based on certain conditions. For example, from our user's collection, we want to get data of all users. First of all, we write the model of that collection, which is the user dot here we get multiple query methods. We have find by ID, and find one. Also, we have other fine methods for update, delete, and replace. Don't worry about those. We will see them in the upcoming lessons. Currently, we just focus on this find, which is used to find multiple documents from our collection. So we have Fine n which is used to fetch only single document from the collection. Also we have Fine by ID, which is used to fetch document by its unique ID. Currently, we want to fetch multiple documents, so we use here dot Find. Now, this expression will also return promise. We can use here then method, or we can use Ising await. In this use case, ain await is simpler and help us to write clean core. Here, we create a new ing function called get users and simply move this await inside this function. Now, this will return the data of all users from the user collection. We store it in variable called users and Consol dot log this users data. Also at the place of this creatuser function, we call GtusersFunction, and move it below this function. Now let's see we are getting data or not. Save the changes. And let's run this application using node index dot gs. See, here we get array of two users data. First one is code plusU and then Harley. Lovely. That's how we fetch all data from the collection. Now, let's make this more interesting. Suppose we want to find only those users whose name is Harley. So to do that, we pass object in the fine method. Here, we can define multiple conditions in key value pair. That's a name two encodes Harley. This will find all users data whose name is Halley. Also, here we can pass multiple conditions like Es verified to false, et cetera. This query will check if the name is Halle and its is verified value is false or not. If both conditions are true, only then we get those users data. Say this and let's run our application. See, here we get empty array. Why? As we can see in our database, we have name Halle and also is verified is set to false. Then why we are not getting this data. Here in the name property, we pass Halle in lower case. But in database, H is upper case. So let's change this condition, see what the changes, and let's run our application one more time. See, here we get our data. So remember, if we pass string for condition, make sure we write in case sensitive. Good. Now currently we are getting data with all fills. What if we just want to fetch the username and hobbies? So for that, after this fine method, can add select method and inside the codes, we pass our fields name separate by space. We write name space hobbies. If we want other fields, then also we can pass here with space. For now, we don't want that. Save the changes, and let's run our application. See, here we get only name, hobbies and underscore ID which is automatically added by Mongo DB. Also, if from our data, we just want to remove one or two fills like here, we want all data except password and is verified. So at the place of these fill names, we pass minus password, space, minus is verified. Save the changes, open terminal, and let's run our file. See, here we get all fails except password and Es verified. Simple. Now let's make this little more advanced query. Suppose we have 100 user data and we want to fetch those data, but how can we fetch 100 data in single array? It's better we fetch first ten data, then after that, another ten data. So here we remove this condition because we want all data and after the select, we add limit inside this, we can pass the number of records we want to see. Let's say ten. Save the changes, open terminal, and let's run our application. See, here we get two records because we only have two records. If we have 20 records, then we get only first ten records. Also, as we have limit, we also skip method. Here we pass the number of data we want to skip. If we have 20 records and we adhere skip five, then it will skip the first five records and then display six to 20 data. This limit and skip method are very useful for paginess and query. Don't worry, I added separate lesson for that. For now, just understand Skip and limit are available. So let's remove this. Good. Now at last, we can also short our data by any filled. Suppose we want to short our user data by its name filled. So we can write here dot short, and inside this, we pass object, and here we pass our field name, which is name, and here we can pass two values one, which is for ascending order and minus one for descending order. Let's pass both one by one. First one, save this and let's run our application. See, we get users with ascending order, which means A to ZD if we change this to minus one, save this and let's again run our file. See, here we get descending order, which is Z to A, and that's why it display har first and then code bless you. Don't worry, I will give you detailed PDF of this section. You can revise these methods as fast as possible. 66. Comparison Operators in MongoDB: Let's learn about comparison operators in Mongodib. Comparison operators are used to compare values in the database with the values we specify in the query, and it is really important when we are working with data, especially number based data. For example, imagine in our users data, we have age filled, and we want to fetch users data whose age are 18-30 greater than 18 or less than 50. It can be anything. When we want to do something like this, we need comparison operator. There are many comparison operators in Mongo Deb. First, we have dollar EQ, which is for equals to. Next, we have dollar N, which is not equals to dollar GT, which is greater than dollar GT E. Can you guess? Right, greater than or equals to dollar LT, which is a less than dollar LT for less than or equals to dollar E. This is used for matching any of the values in the list, age should be 18, 22, 25, like that. Can pass multiple values in array. And at last, we have dollar NIN which does not match any values in array, and it is opposite of dollar N. Comparison operators are really simple. Let me show you where we have to write comparison operators. So to make it practical, let's add H field for these two documents. So Pan Mongo to be compass and go to the user's collection. Here, we can modify each document using this edit icon. Over any of the field. And at the left side, we get plus icon for adding new field. Select add new field, and here we write our fill name, which is age, and we pass value, let's say ten. Currently, this value type is string, but we can change that from here and we set it to integer 32. See, now it is integer. Also we add new field for the second document, fill name, age, and value, let's say 20. As we changed a type to integer 32 and click on Update. Code. Now, in our code, previously, as we can see, if you want to add condition for our query, then we add that fill in the object here, like age to ten. This will fetch all users data whose age is t ten. Let me ask you one question where we can write our logical operator. Because as we can see, for condition, we have to pass key value pair in this find method. So the solution is at the place of this hard codal value ten, we can write our comparison operator in another object. Don't get confused, see this. So at the place of ten, we add object, and we simply write comparison operator as key in this sub object. Let's say dollar GTE, which is greater than or equals to, and greater than or equals to what? 18. So this simply means find all users whose age is greater or equals to 18. Just we replace that hard coded value ten with the object, and inside the object, we use comparison operator. Now let me give you a little task. Let's remove this whole object from the fine method. We want to fetch all users whose age is less than 18. Here we add object, and first, we add on which field we want to apply condition, which is age. And instead of hard value, we pass here object because we want to use comparison operator, and inside it, we use dollar T for less than and less than to 18. Simple as that. Save this file and for the find method, we can run our application using nodemon index dot js because it will not change anything in the database. See, here we get user whose age is less than 18. You can see just we have to pass Object with comparison operator at the place of hard value. Also, these first six operators are very simple, but many students confused in this in and not in operator. At the place of value, here we have to pass list of values. So let me show you these two operators. Suppose we want to fetch only users whose age is 18, 20 or 30. So when we want to compare multiple values for one field, then we use dollar in operator. So at the place of dollar LT, we use dollar in. At the place of value, we pass array of values, 18, 20, 30. Simple as that, save the changes and take a look. See, here we get user with age 20 because we pass 20 in this array. Now dollar NN is the opposite of dollar in. I call it an inside, which means patch users whose age is not 18, 20 or 30. Save the changes, and see, here we get user with age ten. So that's how we pass comparison operators in Mongo DV. Just remember in regular condition, we pass here fill with values, but for comparison operators, we pass here fill with object, and inside this object, we add our comparison operator. 67. Logical Operators in MongoDB: Let's see logical operators. So logical operators allows us to combine multiple conditions in our query. In simple words, they help us to ask more complexes from the database. Don't worry. There are only few logical operators, and they are also simple as comparison operators. First logical operator is dollar R. We will use operator when we have multiple conditions and we want, if any one condition is true, then return that data. Example, we want to fetch users who are 30-years-old or have name Halley. In this case, we want any one condition should be true, and that's why we use here or operator. Let me show you that practically. I comment out this previous code and write cost users is equal to await user dot Find. And in this find method, we pass Object, and in that object, we simply add dollar or operator. Now you might think a comparison operator at the place of value, but we are using logical operator at the place of condition. Let me give you my trig to remember it. As we know, we always compare values, and that's why we have to write comparison operator at the place of value. But we implement logical operators for conditions, and that's why we have to write logical operator at the place of conditions. When I started Mongo Deb I remember it this way. As we know, we want to add here multiple conditions and what we use for multiple conditions, we will use array. Now inside this array, we add our conditions in individual object. So object age to 30 or we pass another condition name H. If any one condition is true, then we get that user data. The changes and take a look. See, here we get the user Halley because its name is Halley. This user age is same as our condition or not. It doesn't matter. If any one condition is meshed, then we get that data. Simple as that. Now suppose we want for our query. These both conditions must be true, which means user age should 30 and also name should be Halley. In this situation, where we want all conditions must be true. We will use end operator. So at the place of this operator, we pass and operator. Now, can you guess the output? Right, we don't get anything because we don't have data where age is 30 and name is h. See, here we get empty array. Now let me show you shortcut way to write this and operator. When we want these all conditions must be true, we already write the same query at the beginning of the query topic. We can directly pass those conditions in the find method like this. These both works the same. But when we want to use operator, then we need to follow this syntax. Now, after dollar end operator, we have another logical operator which is dollar NR, or we call as logical NR. For example, we want to find users who are not 30-years-old and do not have the name Harley, which means both conditions should be false. For that, at the place of this end operator, we pass NR operator. The changes and see, here we get data with name God bless you because for this data, both conditions are false, and that's why we get this data. But for our second user data, this name condition is true, so we don't get that data simple as that. Now the last logical operator we have is dollar naught or logical nut. This logical knot operator is little different because we only use not operator with comparison operators and regular expressions. Don't worry about regular expression. We will see that in the next lesson. For now, let's see, dollar naught operator. Suppose we want to find users whose age are not equals to 30. Again, I comment out this syntax and write again, cost user equals to awight user dot find. Object, and first, we add filled for which we want to add condition, which is H. Now at the place of value, we pass object with operator dollar nu. We write dollar nut operator at the place of value because dollar naught operator is directly related to value not with conditions. Now what we want is age should not equals to 30, we have age and also nought, but we don't have equals and value. We addhe another object with dollar operator, which means equals and simply pass here value 30. Save the changes and take a look. See, here we get both users because both age is not equals to 30. You can see it is really simple. Let me show you one more time. In the comparison operator, we are writing like this. Age column, dollar equals to or greater than or less than whatever operator we want to use to its value. Now here, we just want to add not operator, we simply wrap this object with another object and add here dollar naught operator and colon simple as that. I know this is a little confusing, but don't worry if you don't remember the syntax of operators, I will give you my cheatsheet at the end of this section so you can use it when we will work on real world projects. That's all about logical operators. If you are continuously watching the course, then you can take little break from your screen, listen some music, or take a fresh walk. See you in the next lesson. 68. Regular Expression in MongoDB: Now let's see about regular expressions. What is regular expression? A regular expression is a way to define search patterns for strings. For example, we want to find all users whose names start with edge or we want to fetch all users whose email has gmail.com at the end of their email. In these cases, we will use regular expressions or some developers called it jx. It is really useful in auto suggestions query or search query. Let me show you practically. Here I comment out this previous query. Also, remove old queries and write a new query Cast users equals to await user dot find. Here, we pass object, and on which property we want to apply search pattern. Let's try name. Now at the place of value, we pass regular expression. Here is the syntax of the regular expression. Slash pattern slash. So based on this pattern, we will do many things. Suppose we want to find all users data whose name start with So at the place of this pattern, we use Kerat symbol, which means start with, and here we pass cptalH. This query will find all users whose name start with capital so if we want to find users whose name end with any letter, then I duplicate this line and at the place of this carat, we write dollar. This dollar means end with. So this query will return all data whose name end with U. Now let me give you a little task. We want to find users whose email ends with gmail.com. It is really simple. We change this fill name to email and simply at the place of this, we write gmail.com dollar. Let's see we get the results or not. See if the changes, and C we get both users because they both have gmail.com. Now let me show you something cool. In the Mongo Di B Compass, I change the second user email at the place of gmail.com. I write Gmail, com. Save this, and let's see what we get. Save this file. And see here we get, again, both users. You might ask, even if this email doesn't end with gmail.com, why we are still getting this user data. What is wrong with our regular expression? In regular expression, this period can match any character, which means JavaScript will match it with any character. And that's why if we pass any character at the place of this period, we get that data. Now we might ask, what if we want to compare period as period? Not as any character. It is really simple. Just before the period, we will use backward slash. Now, JavaScript will compare this period as period, not as any character. Save the changes and see, here we get only first user. Also this pattern is case sensitive. I any user have email in uppercase like gmail.com, then we will not get that user in this list. So to remove case sensitive, we have to just add I at the end of our regular expression. Now, what if we want to find users whose email contain Harley? Not start with Halle or ends with Halley. Harley can be anywhere. So in this case, we simply write our word at the place of pattern without adding garret or dollar. So if we want to find users with exact word, let's say developer in the description, not part of another word like developer, we want only developer. In this case, we write pattern like this. Here at the place of this pattern, we write that word, which is developer and before and after that word, we add backwards B, backwards B, which represents the boundary of that word. These are some common and useful regular expressions. If you want to learn more patterns of regular expressions, then you can use this article and read about other patterns because it is pure JavaScript. Also, in current Mangodib version, few developers use dollar RejxOperator at the place of adding direct patterns like this. This both works the same. I like this Sater version, but you can also use this Rjxoperator. It's totally up to you. 69. Count and estimate Document Count: Suppose we want to count the number of documents available in our user's collection. I duplicate this query and comment out previous query. Now when we want to only count the number of documents, then at the place of this fine method, we pass count Documents method. This query works the same as before. We get a number of data in output. In the Count documents method, we pass our conditions or we also pass logical operators, comparison operators, regular expressions, same as find method. Find method returns the actual data, where Count documents method will return the number of document. Let's check this. See the changes and take a look. C, here we get zero because there is no data for this condition. Now sometimes we don't want to add any conditions, only we want total count of documents. At that time, we can remove this object, save these and see, here we get the total number of users data. Now, currently, our data is very small. Imagine we want to count the number of products for big ecommerce applications. Want to display the total number of products available on the platform in the admin dashboard. At the time, we don't need the ext count that shows the total number of products. Now, at that time, we can use another method for counting the estimate number of documents, which is estimated document count. As its name suggests, this is an estimated count. Same as count documents, we can pass this estimated document count method right after the model name. Now you might ask, what is the difference between these two? First one is count documents returns the accurate number, but estimated count display approx count. Another difference is we can pass conditions or filters in the count documents method. But in estimated document count method, we can't pass any condition. It can only count full collection. So count document is little slow than estimated document count. So to summarize, we use count documents when we need to apply filters or we want to get exit count. And at the other side, we use estimated document count when we need a fast and rough estimate of the total number of documents in the collection. 70. Pagination & Infinite Query: Let's see how we can create pagination or infinite query. Before we see the query, it's better we understand how pagination and infinite scrolling works. Suppose we are working on big ecommerce application. In this application, we might have 1,000 or 10,000 products like Amazon. Now at the time, we get all products detailed in single API call. It will take more time and also the load on our server will increase. So instead of getting all data in single request as a Bond developer, we can divide them in pages like we get only eight or ten data in single request. If user need more data, then we fetch next ten data. Don't worry about how we will create this API. For now, just understand how pagination and infinite scrolling works. Here is the front end example of pagination. On first page, we have only eight data after that, when we click on second page button, we'll get next eight data. Simple as that. Let me show you also infinite scrolling example. Here we have eight data, and when we reach to the bottom of the page, it will load another eight data from the back end. See, this is really cool. Now just think in human language, what is happening here. Don't worry about code. Just think what is happening. Pagination and infinite scrolling both works almost same. In both techniques, we will fetch data in small quantity as we need. Just in infinite scrolling, we keep our previous data. Wherein pagination, we will replace the previous data. But back end for the both techniques will stay the same. Let me explain you with 20 records example. These are 20 records at a time, we want to show only four records. We can define variable page per data to four. We get four records from here and we can mark it as page one. Now, if users scroll or even move to second page, then we will skip this page one data, which means we skip per page four data and then fetch another four records from here. Next, when user again scroll or move to third page, then we will skip page one and page two data. Mathematically, we will skip current page, which is three minus one into per page data, which means two into four is equal to eight. We skip first eight data and fetch another four, which is per page data. Every time we increase our page number, we will skip current page minus one into per page data and fetch another data which is the number of per page data. Tell me how many we will skip when we move to fourth page. Right, we will skip four minus one, which is three into four, which is 12. We skip first 12 records and fetch another four data. Simple as that. In Mongoose, we have skip method, which we've seen previously, and also we have limit for just fetch and number of data. So here we remove this query because it can create confusion. Now we write const users equals to await user dot Find here we don't want to pass any condition. Now, after the fine method, we adhere Skip method, and inside this, we have to pass how many number of data we want to skip. For now, we pass directly zero because for the first page, we want to skip zero data. After that, how many data we want in our single page? Right, we want to send four data. So we add here another method called limit and pass here four. This query works for page one. Now let's make this query work for every page. So when you searchange page to two and call this API, we will simply skip first four data. And for that, we created formula in our example. So at the top, we define variable. Current page is equal to say two. And after that, another variable called per page data is equal to four. Currently, as we can see, we hard coded these values. But in real world, these values are passed by the front end. And do you know by which front end send these details? Any guess? Right, front end will send these details using query parameters. Suppose our products API look like this, slash API slash products, question mark, current page is equal to two, and per page data is equal to four or ten, anything our front end developer wants. But for now, I don't want to add this complexity. That's why we hard coded these values here. Now in this kip method, we pass parenthesis, current page minus one into per page data. And in the limit, what we will pass, right, we pass per page data and done. Let me save this so we can see this clearly. Great. Now, if we check our terminal, we get tray because in our database, we don't have more than four data, so we don't get data per page two. If we change the current page to one, save this and see here we get to data. We created query for pagination and infinite scrolling. This single query will work for both features. I hope I explain this well. If you still have confusion, then try to put different values in these variables. I bet you will understand this. 71. Update the Data: Now let's see how we can update the data in Mongo DB. So there are two ways to update data. In first method, we will first find the document which we want to update. After that, modify its property, and at last, we save the updated data in our database. And second method is, we will use update methods of mangos and directly update the document in the database. After that, we have option to return updated data depending on our needs. Now what do you think which method is fast? Now, what do you think which method is useful? Yes, second method is more useful because in the first method, we have to do multiple steps, which might take little long time. But in the second method, we will use methods defined by mangoes, so we don't need to worry about updating data by our own. Also, we will use first method according to our needs. Now there are four methods for updating the document. Don't worry. Every method is very simple and easy. Let me show you that. Here I open MongoDB demo project. And here, let's suppose we want to update our user email ID whose name is code bless. So we create here a sing function called Update User. And inside this function, we will write our update logic. So for Update, we use user Module dot. Here we have Update one method. Now, same as the fine method, we can pass here query object in which we will apply filters or we can say condition. So what is condition here? Username should be code plus. So we have declared which user we want to update. Now we just need to pass which property we want to change. So for that, we pass another object at the second parameter, and inside this, we have dollar set operator and we pass to object. Now in this object, we will specify which property we want to change with its updated value. So we want to change email to updated at the red gmail.com. So we can adhere multiple properties. But for now, we just want to change email. Now, as we know, this expression is Asnruners task. So we can adhere await. Let me save so we can see properly. Good. Now, this expression will not return the updated object. Let's see what we get here. So we store it in variable called result, and simply at the bottom, console dot log this result. Also at the place of this Gate user function, we call Update User function. Now, before you save changes, make sure you stop the application. Now save the changes and take a look. Run this application using node index dot js. See, here we don't get updated user data, but we get some basic information about ddt task. Let's verify how data gets updated in the database or not. So Pamongo be compass and see here our email is changed to updated@gmail.com. So that's how we update the data. At first, we pass query object with conditions, and at the second argument, we pass dollar set operator, and we pass object with updated properties and values. Simple as that. But also keep in mind that this update one method will only update one document, not all documents who fulfill this condition. Sometimes we want to also get the updated document. Don't worry, it is really simple. At the place of update one, we will pass find one and update. This will return the old document before we are updating. But here we want to get the updated document. Forgetting the updated document, we pass here, third object, and in that we pass new to true. Also, as a good practice, we will pass another option here, which is run validators to True. Now you might ask what is run validators? It is nothing we are telling our query to ensure these updated values should follow the model schema. Also, let me change this email value to blessthergml.com. The changes and take a look. Let's run this application again. See now we get here updated value. That's how we can update values using update one and find one and update method. Both are very similar. Update one, don't return the updated document. Where using find one and update, we get the updated document, but these both only updates one document. Now let me give you a little task here. We want to update name of the user whose ID is this. Can you write the query? It is really simple. Here in the query object at the place of name, we pass underscore ID, and we pass here our user ID in string. You can copy your user ID from the Mongo DB Compass and also change this email value to XYZ at achmail.com. Save the changes and take a look. Run this application. See here we get the updated document. Lovely. So this is very simple. Many times, we want to find our document only based on their unique ID like we currently did. We don't want to pass any other condition because this ID is unique and there is no point for passing other conditions. When we want to update data using their ID at the place of find one and update method, we have another shortcut method, which is find by ID and update. Now here we don't need to pass this query object. At the place of that, we directly pass our ID in string. The changes and take a look. Run this application. See, we again get updated document. So when we want to find user by its ID, we will use fine by ID and update. Now we have seen these three methods for update. Update one, find one, and update, and find by ID and update. If you notice, these all methods update only single document which they found first. Two, update one and find one and update their names are showing they are only updating one document. And if we talk about fine by ID and update, what we are passing here as condition, we pass unique ID, which means it will also update only single record whose ID is this. But what if we want to update multiple documents? For that, we have fourth method of update, which is update many. At the place of this fine by ID and update, we add update many. So here we have to again pass your query object in which we will define conditions. So you pass your age to 20. So here we are telling update our records whose age is 20 and update their email to this value. Let me change this email value as hegmil.com. We don't need this third argument, which are options because this will only work for fine one and update and find by ID and update. See the changes, and let's run this application. See, again, we don't get updated document, but if we check our database, our value gets updated. So to quickly summarize, we have four methods for updating data in Mongo DB. Update one for updating a single document, update many for updating multiple documents, find one and update for finding and updating a single document in one step, last one, find by ID and update for finding a document by ID and updating it. Also, in find one and update, and find by ID and update method, we pass Option object in which we will set new to true for getting new updated data also run validators to true to follow the model schema for updated values. Simple as that. 72. Update Operators in MongoDB: Now let's talk about update operators. Update operators are used to modify documents during an update operation. In simple words, update operators allows us to update specific fills, increment values, set new data, remove fills, and much more. Let me tell you something. We already use one update operator, which is dollar set, but we have many other update operators. So head over to browser and type update operators in Mongo DB. Open this first link, and here we can see we have update operators like dollar current date for setting the value of the filled to current date. Dollar ink for incrementing the value of the fill by specific amount. Suppose someone like the post, so we can use dollar ink Operator for increasing the value of the fill. Also in the ink operator, we can pass negative values which can decrease the count. Next we have mean, max, ML for multiplication, rename, set, set on insert, set for removing the field from the document. Also at the bottom, we have operators for array, pull, push, pull all, et cetera. Don't worry about these operators. We will use many of them in our future projects. For now, I just want to introduce to these update operators. In the next lesson, we will see how can we delete document from MongoDB? 73. Delete the Data: Now let's see how we can delete data from the Mongo Div. It is very similar to updating the data. We have four methods for deleting the data. Delete one, delete many, find one and delete, and last one, find by ID and delete. Now you understand why I take more time for explaining update methods. They are very similar to delete methods. Let's quickly see these delete methods. Here, we create a new ASN function called delete user. Now inside this, we use user dot Delete one and what we will pass in this method. We just pass query object because here we just want to delete the document. We don't need to specify what we want to update, we can pass something like this ascore ID to some user ID, which I copied from the Mongo Dib compass. This will remove this single user with its ID. Now we can adhere await, same as before, and simply store its result invariable. This result is the object with deletion property. We don't get here document. Now, let me ask you one thing. What if we want to get this deleted document in the result? Which method we will use? We can use here, find one, and delete. And here, we don't need to change anything. So at the place of fine one and delete method, we can use fine by ID and delete method. But when we use fine by ID and delete, we don't need to pass here object with ID property. We can directly pass like this. I don't want to borrow by showing these methods because they are almost same, right? Imagine we want to delete all users whose age is greater than 15 and they are also not verified. It is really simple. We use here, delete many method, and at theblas of this ID, we pass query object, and inside it, age should be greater than 15. And another property is verified to false. Now let's console dot log this result. And at the place of calling Update user function, we call deleted user function. Save the changes, and let's run this application. See, here we get deleted count to one because only one document is fulfilling this condition. And if we check our database, then see we have only one document. So that's all about delete operation. It is really simple than updating the data. 74. Exercise 01 - Configure MongoDB: Now it is time for exercise, you can practice by your own whatever you have learned in this section. Open up our first project, Task track, which we left in the Section five. We can practice on that project. If you don't have previous project code, don't worry, you can download it from below of this lesson. Now I design this exercise for you to go through various steps of Mongo DB. First of all, step one, I want you to connect this project one with Mongo DB database. You can give this database name, Task track or anything. After successfully connect to the database in step two, you have to create a schema for storing Tudous. In your project, create a new folder called models and inside that folder, create a new file called Tudous dot js. In that file, you have to define schema and model for Tudos collection separate from our other code, and fills should be like this. First, we had task in which we will define the text for that Tudo. Make sure this fill is compulsory. Next fill we have is status, which can be Tudo doing or done. Have to think which field type you want to use. Also, the default value of this field should be to do. Now, last field is text, which is the area of values in which we can add related language texts like SDML, CSS, JavaScript, react, node, et cetera, and that's it for this schema. Now step number three, based on this schema, have to define a model for Tudou's collection. Simple. I know you can do this. I also add this exercise instruction PDF below of this lesson. Also, don't worry if you don't remember the methods of Mongo DB. You can use the summary PDF which I added at the end of this section. The goal of this exercise is you get through the process of the Mongo DB steps. So give your 100% and then watch the solution. I hope you solve this exercise or you try to solve this exercise and stuck in one of these steps. Don't worry, at least you try to solve it. So give yourself credit for that. Now let's see the solution. First of all, in our project, we have to install mangos because without Ted we can't do any other things. So NPM install mangoes at the red 8.8 0.0. God. Let's minimize this terminal. Now in our index dot JS file, at the very top, we input const mangos is equal to require mangos. And after this Studos route, we write mangos dot Connect. At the first argument, we pass an excess ring, which is Mongo DV colon double forward slash, Local host. Column 27017 slash, and here we write our database name, which is TAS TAG. Now, as we know, this expression returns a promise. So we useart then method and inside it simply consult dot log. Mongo DB connected successfully. Now, what if we get error in this? So we also add cache method. Here, we get error Object, error function, and console dot log. MongoDB connection filled. And print this error. So step number one is done. Now step number two, we have to define schema for task. So we create a new folder in our project called models. And inside this folder, we create a new file called todos dot js. Now you might ask why we have to create a new file? We can't define it in our index dot js file. Yes, we can define schema and models into index dot JS file. But imagine our project has five different models. Think how messy our code become we add five different schemas and model in our index dot JS file. This is the real world practice. We will define all models and their schemas in the separate folder, which is models. And whatever model we want to create, we give its name to the file. In this case, it is Tudos dot js. Here we first import Cs mangos is equal to require mangos. After that, we create a new Mongoose dot schema, and inside this, we pass our fills in object. First one is task, and we set it to string. But also, we want to make this fill compulsory. So at the place of this string, we pass different properties in object. Let's say type to string and required to true. Next we have stats to object, again, type two string. And here we want to give the field values. So we write Enum property to array, and here we pass values. First one is to dos then we might have doing, and then we write done. So if we try to enter any fourth value, then these values, then that will not work. Also, we want to give its default value, so default and we set it to todo. Good. Now next, we have text, which is array of string. We can directly pass here array and inside it, we pass string Done. Our schema is ready. Let's store it in variable called Tds schema. Let's move to the third step. Do you remember how can we define model? We use mangos dot model. Here, we first pass the singular name of our collection, which is Todo, which will become Todos collection. At the second argument, we pass Todos schema. Now this will return the todo model. Let's store it in variable called todo. Make sure we use your pascal case because this todos works like JavaScript class. We completed our first exercise. In the next lesson, we will move little forward. 75. Exercise 02 - For Storing Data: Now let's move to second exercise in which we will recall about inserting data in Mango Div. So here is the exercise to Instruction PDF. You can also download it from the right side. Also, I added one JSON file in which I added eight records for Todos. Now in this project, we have already API for creating new todo. But in this API, we are simply pushing new data to our local array. Instead of that, we want to store data in our todos collection. Let me give you here a little hint. We can do anything in the collection using the model. You have to get model from the models folder and use it here. Here is a little demo for you. When we send post API request with this JSON object, in the back end, we will store that data in our database and return stored data in the response. We already done this in this section. You can also use that current section code for reference. Try to solve this and then watch the solution. So I hope you solve it or try to solve it. Now let's see the solution. First of all, we have to insert records in our todos collection. But we know we're doing anything with collection, we need that model. How can we get Tudo model here in this Tu Dos routes file? Right, we have to export our model from Tudos Model five. So we write here, module dot Exports equals to this Tudo model. This will export this Tudo model as default. Save this. In the TudosRout at the top, we import Const Tudo is equal to require now currently we are in the routes folder, and we want to access the models folder. So we have to go back in our folder using double dot forward slash models, and inside this todos dot js file. Good. So we have Todo model in this file. Now let's quickly store that Todos data inside collection. So we move to the post request, which we create for adding new to do inside our local array. First of all, we can comment out this Tudos array dot push method, and at the place of this, we can write Nu to do. And here we pass out to do object. First property is task, and how can we get the task? Right at the top, we get the request body and store it into do variable. So at the bottom, we write to do dot Task. Next, we have status, which we again get from Tudos dot status and also tags to Todo dot tags. Here we are not adding ID because it will auto generated by MongoDB. Previously, in this section, we use here hard coded value, but here we are using values which we get in the request body. Simple as that. Now, this will return a New to do object and to save it, we write here Nut dot save. As we already know, this is async runners task. That's why we use here away. But see here we are getting runtime error. For using Avid, we have to make our function async. But how so here in this API, our function is this started from request and response to this CR bracket. Now to make this function async, before this parenthesis, we pass an keyword. Simple as that. See, error is gone. Now, this expression will return the stored data from the database. So we store it in variable const stored data. And then we send this store to do as response. Now let's see this is working or not. Save the changes and let's run this application using nodemon index dot js. Good server is running, and also we get Mongo Db connected successfully. Perfect. Now using our tender client extension, we will send post request. We have already saved this create to do API, so we will directly use this here in the body of the request, instead of using form encoded, we will use JS and format. Will make our task easy. Now open JSNFle which I attach with this lesson. You can download as you download PDF from the right side. Now, simply, I copy the first to do object and paste it in the request body. Also, make sure you a prefix API in the URL and send the request. See, here we get our new data with auto generated ID. Also, we can check that in the Mongo DbCompass see, here we get the todos data. Now I fast forward this lesson and one by one, insert all todos. Good. You can see how we are progressing and solving each exercise step by step. In real world, also, you have to work step by step. By that way, you get less confused and work with ease. 76. Exercise 03 - Fetching Data: Now it is time for the third exercise, which I design for fetching the data. After adding multiple values in the collection, I want you to write query for this collection. We have already one G method for fetching all to dos. You can write all queries one by one here and complete the exercise. Exercise three first query is we want to fetch all to dos data. After that, second query is Fatudos who has tag, react. Third query, this is a little tricky. Festuds who has tag STML and also a status should Tudo. After that, fourth query count the number of Tudos whose status is set to done. Last fifth query is faz tudos in which task, there is word create, only the word create. It should not include recreate created, only create and also make sure you ignore case sensitive here. As you know, you can use my summary PDF if you don't remember the methods and solve this exercise. This will boost your confidence, and that's how you will learn on which things you need to focus more. Also, if you're confused in one query, then you can move forward with other queries and solve other queries. So I hope you try to solve this exercise. Now, let's quickly see the solution. For first query, for fetching all to dos from the database, here we have this GPI in which we are directly returning this todos array. But now we want to fetch data from the database, and then we will return that data. So here we write todo dot find. We want all todos, so here we don't pass any condition. Now, this expression is promise. We can await here and store that data in variable called todos. Now here we get runtime error. Can you tell me how can we solve it? We make our function async function, and at the end, we will send this todos as response. Save the changes, and let's call this GTI PI. Here we don't have this GIPI so we create a new request, and in the URL, we pass local host column 3,000 API slasTudos and send the request. See, here we get the list of Tudos. So we solve the first query. Now let's move to second query. In these, we have to patch toudos who has tag react. I duplicate this line and comment out first query, now for finding is single string available in the array or not? We don't need to do anything special. We directly pass here, object, and add here condition, text, and in string, we write our keyword, which is react. I in the text array there is any element, same as this react, then we get that to do. Also, we can do the same by using in operator. Both works the same. Save the changes, and let's send this request. See, here we get three to do and all have react tag in them. Now let's move to third query, which is fast todos, who has tag STML and its status should be to do. So at the place of this tag react, we pass STML and we pass another condition status to to do. So we can use your dollar operator, but we already know this also works the same as that operator. Save the changes and take a look. Send the request. See, here we get to Tudos. Great. Now let's move to fourth query in which we have to count the number of tudos whose status is set to done. Let me ask you something. Should we use your fine method or count the number of tudos No, we have something else. Do you remember yes, we use count documents method. So we replace this fine method with count documents, and here we pass condition status to D. Save the changes and take a look. See, here we get five, which means five task status is done. Now we have last query, which is fetching to dos in which task there is word create. Here, we again add fine method and at the place of this status condition, we a task and here we have to use regular expression because we are working with string. Now, do you remember the syntax of regular expression? Yes, it is pattern slash. Now to search a specific word, we use Backwards B, create Bwards B. For making this case insensitive, we use here, I, save the changes and take a look. Send the request and see here we get three records in which we have create Word in task. That's how we fetch data from the database in real world. I hope you get the idea about what we are learning. 77. Exercise 04 - Updating & Removing Tasks: Now let's move to the fourth exercise. Don't worry, you can solve it in just two to 3 minutes. In this project, we also have put method for updating specific to do by its ID. The first query of this exercise is updated specific task by its ID and only change task text to updated to do. As you have to return that updated to do in the response. Here you can copy any object ID from the Mongo Di BC pass and pass it in the query parameter. After that, second query is, you have to update all the documents whose current status is doing and update those status with De. Also, here you don't have to create a new API. You can simply write only update query and check it when I show the solution. At last third query is, you have to delete a specific task by its ID. Here, you can also use any ID from the Mongo Divi compass. And after the deletion process is complete, you have to return object with message property to do deleted successfully. And for delete query, you can use delete API in our code. These are pretty simple exercise. You can use Summary PDF or watching the syntax. Don't worry if you have to watch the syntax of methods. Even sometimes I forgot the syntax. So no worries with practice, you will know this syntax. So I hope you solve this exercise or try to solve this exercise. Give yourself credit for that. Now, let's quickly see the solution. So first query is we have to update the specific task by its ID and change only task text to update it todo. So here we have ID, which we are getting from request dot PAMs. Now from body, we just need task so we can remove other fills. We don't need this code because we write this logic for local array. But now we have MongoDB methods. We can write here to do dot. Now, which method we use here? Should we use Update one, find one, and update, fine by ID, and update or update many? Yes, we can use any of these four. But here, we have to return the updated document. So two options are simply removed, which is update one and Update many because these two will not return the updated document. Now we have only two options. Which one is more simple? We have to update to do with ID. So we use here, find by ID and update, and here we pass this ID. Also, we don't need to convert this ID into integer because Mongo DV object ID is a string. Now in the second argument, we pass object with dollar set operator and we pass here object with task to task, which we get from the body of the request. Now here is one thing. If in object, our property name and value name both are same, which is here task and task. We can simply write it as task. But for giving this code, I'm keeping it this way. Now, do you remember we have to pass third argument in this wind by ID and update method? Here, we pass new to true and also run validators to true. Let's save this so we can see clearly. Nice. Now we know this expression is asynchronous task. So we pass here a weight, and we store updated value in updated to do variable. Also, for a weight, we have to pass here async, and at the bottom, we simply return this updated to do. Save the changes, and let's start this application. Good. Open the updated API test. Here we have body ready. Just at the top, we need to pass the real to do object ID as parameter. So we copy any to do ID from the Mongo Di become pass, and here at the place of this ID, we pass our ID and also make sure we addhe less API prefix. Send this request. Nice, we get our updated data. Now let's move to second query, which is update all the documents whose current status is doing and updated status with done. I duplicate this query and simply comment out this. Now we have to update here multiple documents. So at the place of find by ID and update, we use update many. Here at the place of ID, we have to pass query object with condition status to doing and we want to change the data as done. Also, we remove this third argument. We don't need it, save the changes, and don't worry about ID and task body. We don't use them in our query. Send the request. See, here we get modified count to one, which means we updated it successfully. You can also verify it from the Mongo Di B compass. This is one, right, working with data. I love it. Now let's move to third query. Is for deleting a specific task by its ID. So here we are already getting ID from the request dot PRMs. Also, we remove this past integer method because we don't need it. Now we just need to write query. Remove this previous code, and we use to do dot, which method we use. Think about it. We need to delete specific task by its ID. Yes, we can use Dilt one, fine one and delete, or we can also use fine by ID and delete. Here, I don't specify, we need to return deleted document or not. So for first performance, we use here DLT one. If we want deleted document, then we use here, fine by ID and delete. Here we pass query object with underscore ID property to ID. Now at the beginning, we add await and store it in variable called result. Now for await, at the top, we add Async and at the bottom, we return this result into this JSON object with this message property. Save the changes and take a look, copy any ID from the database and open the delete request At W of this ID, we paste our ID, and also we adhere slash API prefix and send the request. See, we get deleted count to one, which means we successfully delete the todo. If we refresh our database, C, we only have seven todos. One to do is deleted from the database, so that's how we perform update and delete in Mongo DB. I know this section is little long than other sections, but as you can see, Mongo Deb is very important to learn. That's why I designed these exercises specific for learning Mongo Deb. If you're watching this course continuously, then take little break from the screen. Drink some water and take care of your eyes. See you in the next section where we learn advanced topics of Mongo Deb 78. Section 08 - Built in Validators: Welcome to the eighth section of the ultimate Node JS course. In this section, we will learn advanced concepts of Mongo DB. We start with applying validators in model schema, returning custom errors for those validation. After that, we will see how to build relation between collections, different types of designing database structure, and how to make patch very fast. These concepts are very useful when we want to build real world applications. Let's start this section. In the previous section in the Mongo demo project, we created this schema for our user model, and in the schema, we define the type of the fill and some other properties like required. This required is one type of validator for this schema. Previously, we just define them, but we not really see the practical implementation of validator for schema. Let's see what happened when we try to add data without passing the name fill. We cont out this name property from here and at the bottom, at the place of delative user function, we call creative user function. Save the changes, and in the terminal, let's run this application node index dot js. See, here we get error. Let's scroll to the top. Here we can see we are getting validation error, user validation filled. Name path name is required. Now you might ask why we are getting this type of long error. So the reason is we are not handling error properly. So here we know this new user dot cv method returns a promise, and that's why we use await. But here we are pretending we always get data in this object and we forgot to handle error. So do you remember in the Asynrna JavaScript section, how we handle error in Asnawt methods? Right, we use try and catch blog. So here we also add Tr blog move our acing task into it. Now, if you get error in storing this user, our code, move to catch blog. Here, we get error object, and for now, we simply consul dot log this error object, and it has one property called message in which we will get error message. Save the changes, and again, run this application. See, now we get our error message. But here I'm also getting this update information. Let me see what is wrong. Yes, at the bottom, I forgot to comment out this update user function. Save NGs, and let's run this application again. See, here we get our error message. This is good and clear. In real world, we can return this error message as response with Status Code 400. Now, don't worry about that. Now, what if we want to pass custom error message for this required field? At the place of this value true, we pass array. At first place, we pass our value for the required, which is true. At the second place, we pass our error message in string. Let's say, please enter the user name. Save the changes and take a look. See, here we get our custom error message. Validators help us to maintain the quality and accuracy of the data. By using validators, we check if the values in the document follows the rules which we have set for each fill. There are two types of validators in mangos. First one is built in validators, which are the predefined validators by mangos. Second, we have custom validators, which we can define by our own. Required is a part of built in validators. Let me show you another built in validators of mangos. For string, we have min length, which will check minimum length of the string, and we pass the minimum length here. After that, we have max length which will check maximum length of the string. Next, we have match which validates string using a regular expression, and its syntax is slash pattern slash developer use this match validator for validates email. For now, we don't want that. Now suppose for each user, we have to mention the role of that user, which can be simple user or it can be admin, and the string other than this will not valid. So at that time, we set the type to string for setting the two possibilities, we use here num property and we set it to array, and you guessed it correctly, we will pass our values in this array. First, can be user and second, can be admin. We can adhere as many values as we want, but we have to pass one of these values when we save new user. We have already seen this in our exercise. Remember, these are the validators for string. Also, there are two validators for the number as well, mean and max, but we don't want to add them here. That's all built in validators. They are very helpful. Also, one thing I want to make clear is the validators is a mongoose feature. It doesn't do anything with Mongo DB. If from the Mongo Debi database, we remove the name field from one record, then Mongo Deb don't care about in our schema, we set the name field to required or not. Mongoose give us these features so we can validate user values before storing it in database. If it is not valid, mongoose don't store that data in the database, and if it is valid, Mongo store it in the database. Simple as that. Now in the next lesson, we will see how to make custom valid datas. 79. Custom Validators: Now let's see how we can set custom validators in our schema. So here we have hobbies filled, which is the array of string. We want to make sure user must add more than one hobby. For that, we need to define custom validators. It is really simple. So after this type property, here we have another property called validate, and we pass here another object. Now, inside this object, we have validator property, column, and here pass validator function. Here we want to check. Value passed for this field has two elements or not, but for that, we need the value here. We get that value as parameter, and we call it V for value. Now in this function, we can simply return condition. Let me ask you, how can we check this? V has two elements or not? Yes, we can write here, dot Length should be greater than one. And that's it. Let's see it is working or not. For that, we comment out this hobbies field and also I change the email to Harley one. Save the changes, and let's run this application. See, here we get two errors, one for the name and another for hobby. Validator failed for path hobbies with value empty string. Now imagine we return this error with our API. Almost no one can understand this error. So we have to give meaningful error message for changing this error message, after this validator function, we have message property and we pass here custom message, please enter two different hobbies. Make sure we had this message property in this validator object, not in the validator function because I have done this mistake while I'm recording this lesson. Save this and let's run this application one more time. See, here we get our custom error message. Now let's test more things for this fill. What if someone pass only one hobby? Let's check this. Remove the command, and we remove other two hobbies from our array. Save the changes, and let's run this application. Nice, here we are getting the error message, it is working. Now, what if someone pass here null value? Save this and let's run our application one more time. See, here we get cannot read properties of null, reading length. Now why we are getting this error? Because in our custom validators, we try to get the length of this value. But if user pass null as value, we can't access the length property. We can adhere another condition type of V is equal to array. And its length should be greater than one. If these both conditions are true, only then our data is validate. We can also modify message to please enter hobbies array with two different hobbies. Save the changes, and let's run this application. See, here we get the custom message for null value as well. So to quick recap for adding custom validators, we have valid property after the type property. And in that validate, we can add two properties. One is validator, which has a validator function, and another is custom message. And from this validator function, we will return the condition for validation. You might ask if we want to return the condition, then why we need this function? We can directly add condition here, but check this one more time. In this condition, we always need the current value of that fill, and we only get that in the validator function. That's why we need this function. That's how we define custom validators for schema. 80. Async Validators: Sometimes in our project, our validation might involve some asynchronous operations, which means the operation might take time. For example, we want to fetch data from the database, and based on that data, we want to validate our fill. In this case, we can apply Async validators. Let me show you. For applying the Async validators in the previous version. Here in the validator object, we have to add one property called async to true. But in the latest Mongoose version, this option is by default on. We can remove this. Now we can simply make this function async and inside this function, we can perform our asynchronous task. We don't want that complexity or this model, so to demonstrate the delay, we use here set timeout method. First parameter is callback function, and second, we add 3,000 milliseconds. Now before this set timeout function, let me console dot log fetching data for validation. Now suppose after 3,000 milliseconds, we are getting data from the database and based on that data, we can return any condition. Just remember we have to return condition like we returned previously, which means it should be true or false. Save the changes and let's run this application and see, here we get our error. That's how we can apply Async validators. I personally never use this in my project because acyc operations for validation is rare, but this topic may help some of you, and that's why I add this lesson. Now in the next lesson, we will see some schematized options. 81. Useful SchemaTypes Options: Now let's see schema types options in mongoose. We already use them in our schema, which is lower case to true. This will store our string in the lower case. Same as this, we have upper case to true. This will store our entire string in the upper case. And after that, we have another useful option, which is stream to true. This will remove unnecessary blank space from our string. For example, this will convert this string into this type of string. So our data looks well organized and clean. It's not necessary, we have to use all these schema options in our project. We can use whatever is needed according to our model. There are no rules for that. At the end, validators are just for maintaining the quality and accuracy of the data. 82. Relationship between models: So till now in this course, we have seen models or collections which are simple and don't have connection with another model. But in the real world, most of our models are connected to each other. Let me explain you with the example. So imagine we are working on social media application like Twitter. So in that, we have one collection for users in which we will store all users data like name, email, password, et cetera. After that, we have one collection for post in which we will store all post data. In the post document, we have content, which is the post content text date when this post was created. After that, we have user who uploaded this post, let's say Harley. Now, these two documents or we can say collections are not connected to each other. We have to connect them. This is called a relationship of model. Now you might have question why we need to connect models with each other? Why we need that relationship? So if we don't use relationship, we might end up with storing the same user data repeatedly for every post they make. Suppose one user posts ten different posts. If we don't use relationship, then we have to store that same user data ten times for each post, and that's only one user. Imagine on our social media application, there are 100,000 students or more than that. Think how much data have to repeat in our database, and this is also harder to manage. So we have to use relationships between models which have association. Now there are two approach to implement relationship. First one is using references, and another one is embedded data in another document. Let's first see how we can implement relationship using references. In the post document, we have this user and we pass user name. Now, this user already available in the user's collection. Instead of storing user name in the post collection, we can use your user ID of that user. By user's unique ID, we can run another query for getting the user data like name and profile picture from users collection. Now for every post, we have just user ID at the place of user name. But we can see have to run another query in this approach, which might cause performance issue. I'm not telling it will definitely cause performance issue, but sometimes it can. The another approach which can solve this issue is embedded data in another document. At the place of passing here user ID, we can pass here user object and we remove our user's collection. This approach, we don't have to run to queries, so we don't face here performance issues, but here is one thing. Imagine that user has 20 to 40 details. That will make our post document much bigger. Also, it will cause data duplication because for each post, we have to store user object. Now, some developers say these days database storage is cheap. We can afford the data duplication and that's true. But what if our user wants to update its username or email ID? That time, we have to update multiple post and if somehow two to three documents don't get that updates, then that will lead us to data inconsistency. But when we use references, we have to update data only at one place. To sum up, when we use references, we get data consistency because our data is stored at single place, but we might get performance issue because in that we have to run multiple queries. Other side, when we embed data in another document, we get performance. We get our data faster because we don't need to run multiple queries. We have our data in single document, but with that, we get data inconsistency because we have same data at multiple places. This is buy one get one free. We have to decide for our application. We need data consistency or we want performance. If we want data consistency, then we use references, and if we want performance, then we embedded data in another document. Different projects have different requirement. As a developer, you have to decide which approach works best for your project. Nowadays, developers use hybrid approach, which combines these two approach, and we will see that in the next lesson. 83. Hybrid approach for Relationship: We have seen when we use references, we get data consistency, and when we embed data in another document, we get performance. Let me show you the hybrid approach which developers use nowadays. Suppose we have users which have 20 to 30 properties, we will store that users details in the user's collection. Now for post, we have these other fields, same as we see in the reference approach. But in reference approach, we store here user ID. The place of that, we can use here, small user object, which contains only necessary properties which we want to display with post. We might have user ID, which is the reference to the user's collection and the user name. We don't store here all 20 to 30 properties, but we will embed only that much data. We want to display with post. With this approach, we can quickly fetch post because we don't need to fetch multiple queries. We have all necessary data in single object. This approach works best when our collection needs small details that are frequently accessed. For example, in our e commerce project, where we have products, orders, cart, et cetera. Each order, we want to use small details of our products like ID, name, cover image, and price because we want to display that order details with the products. So we have separate collection for products data, but still we will embed some small data about products in each order. So when we want quick access to small details, but we also want to reference large or complex data, then we use hybrid approach. Again, I'm telling you you don't have to stick to one approach. Some application works best with references. So works best with embedded data, and some works best in this hybrid approach. You have to decide according to your project's needs. Don't worry when we build other two projects, I will show you how we can decide relationship approach. I'm talking about relationship between collections, not about other types of relationship. 84. Applying Reference Approach: Let's see how we can apply reference approach for relationship. For practicing this concept, I created this new file because I don't want you get confused by that messy core. Let me explain to you what I added in this file. First, we connect this file with Mongo DB database called Mongo that's relationship. After that, as we see in the example, we define here simple user schema with only three fills, name, email, and age. After that, we define a new schema for post. In that we have two fills content, which can be text and then date, which is the current real time date. We have user which we will add in just a minute. After that, we create two models for users and post collection. We already done this. I don't want to bore you by writing the same code again and again. Now, after we create these two collections, I define few functions. One is for create user in which we can create a new user and store it in user's collection. Next we have Create Post function in which we create a new post using content and user data, who created this post. Last function is for getting all post from the database. We have already seen this all. Let's create first user with these values. Run this application using node, reference dot JS. Good. Now let's try to create a new post without adding any user data. Here I comment out this create user function and remove comment from Create Post function. Let's run this application again and see here we create a new post. We have content and see, we don't get any user data, even if we pass user as filled in the new user data. We can see mangos will only add those fills which we defined in the schema. It will not add all other fills. Now in this post model, have to add the user field and we give user reference from users collection. Let me show you what I mean. Here, we add user. Now whenever we want to give reference, we can give that by using object ID because it is unique. We pass its type to Mongos dot schema dot types, dot Object ID. Yes, we have to pass this expression for define object ID as filled type. After the type property, we have to tell which other model reference we are adding. We pass RF two and here we pass our collection name in singular word. Same as we pass in this mongoose dot model method, which is user. Now let's pass our user ID in the create post function. In the Mongo D BCmepass we get the new database called Mongo relationship. In that, we get users collection, copy this user ID, which we just created and paste it at the place of this users string. In the Create post function, we had this ID at the place of user. Also let's change this content to content too. So the changes, and let's run this application. See here we get new post with content too, and we also get here user ID, which is the reference to user model. Adding a reference is very easy. We have to set that fill type to Mongos dot schema dot Types dot Object ID, and we pass ref property for adding the reference model name in singular word. Now, if we try to get post, so comment out this and remove comment from this G post function. Save the changes and take a look. See, here we get two post. First one, which we created without user and second one in which we define user ID as reference. Now you might ask we are getting here simple user ID. How can we get the user data like username or email from that reference? This we will see in the next lesson. 85. How to extract data from Reference [Populate]: Let's see how can we extract data using this reference ID? It is really simple. For getting the data by reference, we use one method called populate. After this fine method, we add dot populate and inside this, we have to pass the fill name which is the reference. Yes, it is user here. Save the changes and take a look. Run this file again. See, here we again get to post. In the second post, we get all details of that user ID. Now imagine we just want to get here name. We don't need other fills. Can we do that? Yes, we can. At the second argument, we pass pills name which we want to get from our reference collection. In codes, we add name, save this and let's run this application one more time. See, here we get only name and underscore ID. Now, instead of only showing the name, we want all details about user, but we only don't need this age. How can we do that? Ay place of name, we want to remove, minus ge Very simple. That's how we extend reference data using popular method. Now let me tell you something. We had reference in our model, only mangos use that reference. Mongo Deb don't care about that. Even if we pass here invalid user ID, Mongo DB don't check that user ID is available in the user's collection or not. It stores the data without worrying about it. Let me show you that. We create here another post. Comment out this Gad post function and remove comment from this create post function. Let's change this content to three, and we simply modify this user ID last character. In our user's collection, we don't have any user whose ID is this. Now let's run this application. See, our user three is created here. Now let's get the list of post, comment out this function and call this Gad Post function. The changes and see for the third post, we get user to null because we don't get a reference for that invalid object ID, which proves MGB don't verify that user ID is available in the user's collection or not. Now in the next lesson, we will see another approach which is embedded in another document. 86. Applying Embed Approach: To apply embedded approach, I don't remove the previous code because I want to give you this code for reference. We download the file embedded dot JS from the below, or you will get that in the resources section eight folder. Now in the reference approach here for user filled, we pass type to object ID and reference it with users collection. But in the embedded approach, we directly add here user object with all properties. We don't create here user model, delete this line, we only create one model which is post. Also, we can remove create user function from the bottom because for each post document has a user object. Now we can add here object and we have to pass here properties which we need for this user object. We can say name to string, email to string, and age to number. Now the bad thing about this user object is our user can pass no values for the name, email, or age. We have to pass the validations for these fills because we need user object in each post. So instead of adding here validation, we already have user schema. So at the place of passing this simple object, we pass here user schema. This schema, we can add all our validators just as we have separate collection. Also, for defining the schema separately has one more benefit. We can also use that user schema for another collection in which we also want to embed user's data. Now let's create a new post with this embedded user data. So I remove this create user function call, and we call Create Post function. Now at the place of this user, we have to pass user object because that user object will directly get stored in the post document. For user, we pass object with properties name to code email to code etheridgmil.com. Age, let's say 25. Save the changes, and let's run this embedded s file. So node, embeds, and hit Enter. C, we get new post with user object which have name, email, and age. And if we also check our database at the bottom, we get post with user object. So in the reference, we simply pass object ID and add reference to other collection. But in the embedded approach, we directly add whole user data in the single document. Now I have one question. What if we make this name field required and then don't pass name in the user's object? Will our post create or not? This is not a part of lesson I really wants to see. Let's et this. Here at the place of name to string, we add object, type to string, and required to true. Now at the bottom, let's remove this name field and let's change this content to trial error. Save the changes and take a look. Oh, we get validation error, which means new post is not created, and we can also verify that in our database. Now imagine we want to store 20 to 30 properties for users data. We can't add all those fills in the each post document. A, suppose we want to get users data like email and password then how can we get those data separately without fetching all post? This embedded method is not really practical for social media types of application. That's why developers use hybrid approach to bring balance in the application, and we will implement hybrid approach in the next lesson. 87. Applying Hybrid Approach: Let's implement the hybrid approach in the same code template. I again add the same code in the hybrid dot js file. You can also download it from the below of this lesson. Now in the embedded approach, we added all users property in single collection and we don't even create user's collection. Now in the hybrid approach, we create users collection in which we can add all properties. But what we will add in the user's field of the post collection because this post document needs users data who created that post so instead of passing here all users property, we only add few properties which we required with post. For example, with post, we want to show user name and the email of that user. We don't want there, so we addre name, which can be string, and we want to show the profile picture of that user, which can be string of URL of the profile picture. So we adhere only necessary fills for the user. Not the whole document. Now, this will work perfectly fine. But what if maybe in some case, we want more information about user with the post. Some developers also adhere user Rf, which is the user reference. It is the same reference we added in the previous reference lesson. We said it's type to Mongos dot schema dot Types dot Object ID. What we add here yes ref to user. Also, we can change this field name to user summary. I think this is much better. Now let's change a little bit in the create post function. Here, we add user ID in the parameter, and in this post, change this user field to user summary and after that, another property use a ref to this user ID. Now at the bottom, we call this create post function. Here we can change the content. This is hybrid way and pass your object name to codes and profile picture to profile dot JPG. For user ID, I copy the ID from the database. And paste the ID here. Save the changes and take a look. See, here we get new post with user summary and user rep. We get here both. If you want to quickly show data without calling multiple query, then we will use this user summary and if we want more data of user, only then we use this user reference. By this way, we can optimize the performance and also we get data we want. Use what works the best for your application. At the end, this isn't is yours. 88. Indexes in MongoDB: Now let's talk about indexes in Mongo DB. Indexes is very interesting and important topic of Mongo DB. Index is used to make our database query fast, and we will also see the demo of that. Even Mongo DB says that with indexes, our database search query can execute Tenex faster than before, which is really advanced and cool. Now you might ask how index makes our search query faster. Let me explain you with the example. Imagine we have here list of hundred users data and we want to find a user whose email is this y123 atgmil.com. Now how real query works, I pick up one document object, check its email is he 123 aterra gmail.com or not. If it is not, then it will move to another document object and again check that email. It will continue this process until all hundred users document are scanned. As you can see, this is a little slow. What is the solution here? We will create index for our collection filled email. By just creating the index for email filled, our search query for email will become faster. Let's see this practically. In our users collection, currently, we only have one user. Let's add some fake user's data in our collection. So we can practically see our query is working better or not. For that, in the resources section eight folder, I added one file, testing index dot js. Simply at this file in our project. And in this file, I added almost same code as before. First, Mogadbi collection, here you have to write your database name which you are using for this section. Next, we create the user schema with name, email and password, so we can focus on our query. Then at the bottom, we have functions. First one is for insert some random data in the user's collection. See, by using this simple for loop and this faker package, we can generate random user's name, email and password for testing. For that, in our project, we have to do NPM install at the red faker Js faker, at the rate 9.6 0.0. And hit Enter. Good. Now, let's simply call this function to generate 100,000 users data because here we are running this loop 100,000 time. And here we don't want to get error in the adding email, so I remove the unique fill to true from our schema just to allow 100,000 users to enter. Also, from your database, remove this users collection, so we get all fresh data. Drop the collection and type here users and drop the collection. Now in our testing INExis file, we call here Insert test users function. Save this and let's simply run this file. Node testing in axis dot js and hit Enter. It will take little time and see here we get success message. If we check our database, refresh the collection, S in the user's collection, we get 100,000 users data. Lovely. Now first, we comment out this inset this data function. We don't want to run it anymore. Now let's see what finding user by email, how much time it is taking. At the bottom, we have function called find user. In this function, first, I declare time. After that, we run user dot Fine query in which we are passing email to email parameter. After completing this query, we again declare timer, which is the end time, and here we simply show end time minus start time. By this, we will get how much time this fine query is taking. Also, performance dot now is more precise and reliable for measuring execution time. Now, let's call this fine user function. Then from our user's collection, let's copy any email and pass that email in our fine user function with codes. Save this and in the terminal, we terminate the code and run again our tasting index dot JSFle. See, here we get time 130 milliseconds. Now let's create index for our email fill and taste how fast our query will become. For creating index, here before we create collection, we add userschema dot index and inside this, we pass object email, which is the fill name, we want to mark as index, and as value, we can pass two things one and minus one. Now you might ask, what is the meaning of one and minus one? It is really simple. One is for ascending order and minus one is for descending order. When we create index, Mongo DB shot that fill data in ascending order or descending order. This will help Mongo Deb to find data quickly. Don't worry, I will explain you that after tasting. Here we pass one for ascending order and done. That's how we create index for email filled, one line of code. All other code in this file is for tasting, don't worry about that. We just want to see by creating index, our query is becoming fast or not. So here we again run this same find user function and let's run this file. See, here we get 133 milliseconds. Let me run this file one more time. See, now it just takes 76 milliseconds. I get this much time because in my system, currently many large softwares are running. Previously, when I taste this without any software, it is taking 60 milliseconds before adding the index and after adding the index, it only takes four milliseconds. Is almost 15 ngs faster than without index query. This is really interesting. Also, we are getting query time in milliseconds because currently our application is running locally and also our database is local. If we deploy both things on the Internet, then the 130 milliseconds can become 1.3 seconds with index, we run that same query in 0.7 seconds. Imagine how fast our website becomes that's why indexing is very useful. Let me show you index which we created. Open Mongo Divi compass, we go to the indexes Dab. See, here we have two indexes. First one is for underscore ID, and second one is for email. So in the Mongo Di B collection, Mongo DB always create index for underscore ID filed, and that is the reason when we search data by its ID, then we get those results quickly. Now here at the bottom, we have another function called width index. In this function, first we create index manually using this line, and then we write fine query. At the end of the query, I use this explained method. The explain method helps you to analyze how Mongo DB execute a query. It shows whether Mongo DB is using an index or performing a full collection scan. Inside this explain, we pass the string execution stats and simply unst log these users. Let's see what we get inside this. Here at the place of fine user function, we add B index function and let me simply move this at the bottom. The changes and take a look. Let's run this application using node, tasting indexes dot js. See here we get all details about the query like execution stats, commands, server info, and much more. Here we just need to see execution stats. Here we can see and return to one, which means one data is returned from the squery if we see total docs examined, which is also one, if we don't create here index for email field, then these total docs examined will be much higher than this. Let me show that also. Here we have without index function. First in this function, I remove all index from our users collection, and then we run the same query with explained method. Don't worry in our real node application, we will only use userschema dot index method when we define the schema of the collection. I added these two methods to just remove and add index using function. Now let's call this without index function and pass here the same email. Now again, run this file, node testing indexes dot js. See here in the execution states, we get the number return to one and total docs examined to 100,000. That's why it is taking more time than with index. Previously, if we check with index, we get total docs examined to one, and that's why by creating index, our query becomes fast. Now you might ask how by indexes our query is becoming this much faster? What is happening here? We will see that in the next lesson. 89. How indexes works in MongoDB: So previously we have problem. Our database query is scanning all hundred thousand documents one by one for finding specific email which is making our query slow. And we solve that problem by simply apply index for email filled. But the main question is how? What is happening behind the scene when we apply index? Let me explain you with interesting example. Imagine you are in a library with 100,000 books. Now, you need to find book titled Harry Potter. Now if the books are not arranged in any order, you have to start from the first book, checking each title one by one and continue that process until you found Harry Potter book. This is like scanning all 100,000 documents in Mongo Di B without an index which we can consider as slow. Now, let's say library creates an index, something like the list for storing the books information. That list, or we can say in that index, we have book titles, which we sorted alphabetically, and we also add a pointer to the exact self or location in which that book is placed. Now when you search for Harry Potter, you go to the index, find Harry Potter in seconds because it is sorted alphabetically, and then with the book title, we add the pointer. You use that pointer to directly go at the book. Instead of scanning 100,000 books, you find your book in just a milliseconds. In Mongo DB, also, when we create index, Mongo Di B create a tree like structure, which we called as B tree or balanced tree and short our data in ascending or descending order depending upon we pass value as one or minus one. With that fill, it's stored pointer which does the original document location. By creating index, we reduce the number of document scan and because of that, our fine query becomes f for that fill. Now you might ask the shorted data, also, we have to find our data, how it is taking less time than checking all documents one by one. This is the really great question. Let me explain you that. The thing is, suppose if you have unsorted array and a shorted array in both, you want to find element 60. Then in the both array, we don't need to scan each number how can that sorted array takes less time? As we see previously, when we create index, Mongo B creates Battery or balance tree structure with pointer attached to each data. But in this Battery, Mongo Dib also has to search data, and for searching the data, Mongoi use another search technique, which we called as binary search. So when we don't create index, Mongo Db use linear search technique, which means Mongo Db checks data one by one for all documents. And if we create index, then Mongo Dib use binary search technique. Let me explain to you quickly how binary search works so you get better understanding. Imagine here we have shorted array of numbers ten, 20, 30, 200. In this array, we want to find 60. Now there are two ways. First, we check ten is 60, no, 20 no. 30, no. 40, no. 50, no. 60, yes. So here we search all items one by one, which is the example of linear search. Now let me explain what is binary search. In binary search, we make jerms on half. So here at the place of checking ten, 20, 30, we directly jum to the half of the list, which is 50. Here we check, 50 is greater than 60 or less than 60. Yes, 50 is less than 60, so we move to the right side of the list. Now our list is 50 to hundred. In this, we again jump on the half. Tell me on which item we will jump. Right, we jump on 80. In that, we again check, 60 is greater than 80 or less than. It is less than. So if our number is less than, then we move to the left side. Now 50-70, we again jump on the half, which is 60, and we get the element. So at the place of getting 60 in six atoms in linear search, here we are getting 60 in three to four atoms. This is really fast. What do you say? And this is just a ten data. Imagine we have 1 million data, then how much time we can save by using index. So that's why index makes our searching more efficient and it takes less time than linear search. Also note that binary search works only on sorted array, and that's why when we create index, we pass whether it should ascending array or descending array one or minus one. Now you properly understand what is index and why it works really fast. Now, is that mean we need to create index for every field in our database? The answer is no. We have to create index for only those fills for which we want to search. Suppose we have users data and we want to search users by name. In that, we can create index with filled name. So Mongotbcmmand, only use index for large collection in which we are going to store thousands or millions of data. You might ask why we can't create index for small collection or for every field. The reason is when we create index, as we know, Mongotb creates Btree structure, but that Bitr is also stored in our database, and that requires space. Let me show you. Open Mongoib compass and go to our database. See, here we get users collection. Here is the storage size of our collection, which is 6.65 B at the right side, C, we have total indexes size to 3.86 B, which means our data is only three MB and other 3.86 B is just acquired by indexes. So more than 50% is acquired by indexes, which is really huge, and it is just two indexes. If we create index for all fields, then how much it will take our storage. Also, when we have small collections, then our linear search will also run fast. Difference is ignorable and that's why we don't create index for small collections. When we need to apply index, first, when we have large collections, indexing helps use datasets like millions of records. Without an index, Mongo Di B checks each document one by one. Second, when searching is frequent. If we often search for a fill like email, user name, order ID, then we can index it. For example, in user logging system in which we search user by email. This boosts read speed significantly. Next, third, when shorting is common. If we often use Short Method by Price, then we can index that filled price. For example, in the ecommerce product listing. The time, we want to short products by price or date. Index avoid full collection scan. Number four, when we use fills in find update, and delete method. Index speeds up these operations. Now let's also see when we don't need to apply index. Number one, when our collection is small. If we have only a few hundred documents, then searching without an index is already fast. Number two, our data is constantly changing. Indexes slows down, inserts, updates and deletes method, because Mongo Di B must have to update the index tree every time. For example, a log system. In that, new logs added every second, and this will slow down if we create index for logging. Number three, when we already have too many indexes, each index uses storage, too many indexes is equals to vested disk space. So the solution is only index the most important fills. Number four, when we are quering many different fills, we should avoid index. So if our searches varies a lot on fills like name, email, age, city, indexing, each one might not help. So the solution is only index frequently used fills. So to quick recap, we create index in Mongodi B when we have big collection. We want to make our query really fast. Don't worry, we will apply these indexes in our project when we need it. Now, from the next section, we will start building our Project two, which is Ecommerce application backend. 90. Section 09 - Project 02 and Planning: It is time to create our second project. In this project, we are going to create Ecommerce application Ben. We will not create front end because that is not scope of this course. For that, I have separate reac JS course. Now when I start a new project, I like to plan the project roughly. It will give me clarity, and also I recommend you to do the same. So first of all, we have to visualize the basic front end, not perfect design, just visualize. For example, here we are creating ecommerce application. On that website, user can create account or login on the website. After that, they can see the list of products and when they click on that product, they can see full details about that product, more images and description. It doesn't matter user is logged in or not. All users can see products. After that, user can see their order history. Also, they can add product to card, remove product from card, and place the order by payment. So these are the features we need for our project. Don't worry if you don't know all features about your project, as I told you, this is just of plan. In future, we can add or remove features from our application. So first, we will start with creating the user model create API for user authentication. After that, we will move to products, then card, and then orders. You will love this and also you will get the confidence to create no projects by your own. Let's start this amazing project. 91. Creating a new server: Now in our projects folder, let's create a new folder for our second e commerce project called cart Wish Backend and simply open this project in the VS coe. Good. Now when we create a new project, what should we do? Right. We will initialize the project using NPM int Y. This will create a package dots and file. Now here, we create a new file called index dot js. Let's create Express server for this application. Const Express is equal to required Express package. After that, we're creating Express app, Const app is equal to, and we call here this Express function. Now let's listen this server, so app dot LISN here, first we pass port, but at the place of passing hard coded value, we create here variable const port is equal to process dot nv dot Port or 3,000. So if we have port in the environment, then it will use that else we have 3,000, and we simply pass here port at the first place. And what we will pass at the second parameter, we pass here callback function and simply consol dot log. Server is listening on port, dollar Ci packets, port. Now, let's run this application and check we have done this correctly or not. Why I think we might get here error? Let's see, error in developers life is constant. Don't get afraid by that. Open up terminal and run here nodebn index dot js. See, here we get error. Oh, we forgot to install Express package. So NPM install Express. And if you want to use the same version as mine, then write at the rate 5.1 0.0 and hit Enter. Good. Now let's try again. See, here we get server listening. Now in the next lesson, we will connect this application with the database. 92. Connecting to Database: Let's connect this application with a database because we need to store information about users, products, et cetera. First of all, in our project, we have to install mangos. We will not repeat the same mistake. Open up terminal and create a new terminal from here. By this way, we don't need to stop our application. So NPM install Mongoose at the red 8.13 0.2. Good. Let's minimize this. Now in our index dot s file, we import const mangos is equal to require mangos. And after this app, we write Mongos dot connect. At the first argument, we pass our connection string. If you don't remember the connection string of Mongo Di B, you can get it from the Mongo DB Compass. Here in the side bar, we have this local host connection, and at the right side of that, we have three dots option. Here, we get Copy Connection String. And paste it at the first position. Now, at the end of this connection string, we add our database name, which is Card fish. Now, as we know, this expression returns a promise. So we use here dot TN method and inside it simply console dot log. MongoDB connected successfully. Now, after then method, we also add dot cache method for handling errors. Here, we get error Object, error function, and gonsol dot log, MongoDB connection, failed, and print this error object. Now let's test this implementation, save the changes, and in the terminal, see, here we get Mongo DB connected successfully. In the next lesson, we will design our user model. 93. Exercise - Creating User Model: Let me give you little exercise because we have already did this. So you have to create user model for this project. You have to decide which users fill we want for this project. Don't worry if you add more fills or less fills, but the important part is, you think about fills. So remember, which are the features related to users, and according to that, decide the user's fill. Define a schema for those fills and then create model with that schema. After completing this exercise, you can see the solution. Now let's see the solution. First of all, we will create here new folder called models. And inside this folder, we will create a new file called users dot js. Good. Here, first of all, we import Const Mongos is equal to required mangos. Because without mangos, how can we create schema or model? Cost user schema is equal to new mangos dot schema. In the Cali brackets, we will pass our schema in key value pair. First of all, name to object, we set its type to string, required to drew, and we set mean length to three. After that, we can set Emil field and we set its type to string, also required to true we also need unique to true because all users should have only one unique email. And for the best practice, we will also add lowercase to true. After that, which field we can add, yes, we can add password, type to string, and also we have to required to true. After that, for e commerce user, we need delivery address to deliver the product. So type to string required to true, and also we set mean length to five. After that, we can specify the role for each user, whether he's user or admin. So we set it's type to string. We can restrict the role field only two options by using Enum property to array. Here we pass our values user or admin. Also, we can set its default value to user. If we want to change the role to admin, then we have to access the database. By default, all users role set to user only. I think that's pretty much all fields for user model. If in future, we need more functionality, then we can also modify the schema. Don't worry about that. Also, if during the exercise, you take different names for these fills, then you can change them, same as mine. Otherwise, it will might give you bug in the future. Now we have user schema ready, so we can create model using this schema. So Const user is equal to Mongos dot model, and what we pass at the first position. Right, we pass the singular name of the model which is user. At the second argument, we pass user Schema. Also, let's export this user model. We will need it in the user's route. Module dot exports is equal to user. Perfect. Now in the next lesson, we will create first route of this project for creating new user. 94. Creating the new user: Now let's create an API for creating new user. Here, we create a new folder called routes. In this folder, we will create all our routes in separate files. Create a new file users dot js. Now, do you remember how can we create API in separate file? If we have to create API in our main index dot js file, then we can use this app variable. But how can we create API in separate file? Right, we will create router for that. So first, we input Express is equal to required Express. After that, this express has router method which we can call. This will give us router. Store it invariable router. Good. Now let's create API for creating a new user. Which method we can use here, get or put, we will use post method. So Router got post. Here we write our endpoint, which is forward slash, and after this endpoint, we will add callback function, which will run when someone call API with this endpoint. This function has two parameters request and response, and error function. Now, first of all, in this function, we want values which user pass in the request body. So const user data is equal to request dot body. Let's Const dot log this user data. And after that, simply responsdtsN or we can use here response dot JSON because we are sending JSN data, which is this user data. Now let's check our API is defined correctly or not. I like to take small steps because it will not create confusion. This is working, then we can move to main logic. Currently, we define API here, but we have to add this route in our index dot js file. Otherwise, it will not work. We know this right. So let's export this router using module dot exports is equal to Router. Save this file and head over to index dot js file. Here, after the Mongo DV connection, we can add app dot U and at the first position, we will add our API prefix, slash API slash user, and at the second position, we have to pass Router, which we export from users route. So at the top, we add cost user routes is equal to require here periods. Here we go to the routes folder and inside it users route. Now we can simply pass this user's route here. We already done this. Remember, and don't worry if you don't remember the syntax, it is completely fine. Many times, I also forgot the syntax. For now, focus on building the application. Save the changes, and let's test this user API. So on tender client here we can see our previous activity, but I don't want to mix things with the previous project, we go to the collections and from the right side, we have option new collection and give it a name cartwis. We will add all our API taste in this collection. The right side, we have more options. Click on Create New Folder and give it name users. So in this users folder, we will save all our API taste related to user. You can see how systematic this looks, and if in the future, we visit this project, we don't get confused. So we create a new request and give it a name. Create a new user. Select the method to post, and we enter our APIURL which is DTP, Column Abo forward slash Local host, Column 3,000, or whatever you use as port APIs user. Don't forget to add this prefix. To send data in the body of the request, we select your body and we will pass data here in the JSON format. Object, first field name, make sure we write in double codes. Value to code plas Next, we have email to code at the red gmail.com. After that, which fill we add, let me check in the user's schema. Yeah, we have password and delivery status and both are required. Password, and in string, one, two, three, 45678 and delivery address to let's say XYZ, at XYZ. Make sure we use the same filled name as we used in the schema. Otherwise, we get error. Now, let's send this request. What do you think? Will it work or not? Let's see. Send the request. See, here we get 200 status, which means okay, but we don't get our data in the response of this request. Let's check Console A. See here also, we get undefined. Can you guess why this happen again? Remember, when we want to get data from request of the body, we need to use one middleware for converting the data into JSNFmat. Now you remember, in the index dot js file, before this route, we add app dot ug for adding middleware and we simply pass here express dot Jason. By this, we will get data from the request of the body. See if the changes. Let's send the request again. See, now we are getting the data in the response, our current implementation is working. Now let's save this data into our user's collection. But before saving the data in the user's collection, we need to check whether this user is already exist in our database or not. Don't get confused, see this and your allots will clear. Here, we need user model for running the query. Cost user is equal to require here we have to go one folder up, period, period, slash models and we go to users model. Now, after this user data, we can do something like this user dot Fine. Here we pass object for filter. Here we will find user by its unique email and for value, we pass here userdata dot email. So we are finding user, which email is same as this userdata dot email. Also, here is one thing. If we don't have any user whose email is same as this userdata dot email, then this find method will return empty array. So instead of this find method, we can use here Find one method. If user don't exist, then this find one method will return undefined, and that will help us in writing the condition. So we will use here Find one method. As we know, this expression will return promise, so we have to await here, and for using await, we have to make this Cavey function an. Good. Now, let's store the result in the variable called user. Now you can simply put here condition. If user is available, then we will return error in the response. So response Dodge status to 400 for bad request and also in the response want to send data, so dot Json, and here we pass object with message user already exists. Now here is one thing. If user is already available, we don't want to run this bottom logic. To do that, we have to pass here return before this response dot Status. Otherwise, it will run the code forward. What if user is not available in the user's collection? Right, we will store the user data in the collection. So const new user is equal to new user, and here in the object, we pass our data. So name to userdata dot name and email to userdata dot email. Wait, here we have to write user data multiple times. Instead of that, we can destructure our object here. So at the place of user data, we add Object and pass fills name which we get from request dot body. This is called as Object destructuring. So we have name, email, password, and last delivery address. Make sure we write here the same filled name which we pass in the request dot body. Now at the place of userdata dot name, we can write only name. Also if the property name and a value variable name is same, then we can remove this. But for your understanding, I'm not removing it. Email to email password to password and delivery address to delivery address. Also, we have to change here in the fine method, email to email. Now we have new user object, so we can save it in our database, new user dot c, and this is the Async operation. That's why we adhere await. Now, this will return the stored user from the database. If we don't want to return the stored user data, then we can also use this new user data. Don't worry, we get ID in both objects. So at the bottom, we adhere response dot status Tell me status code we will use for new data. Right, we use 201 dot Json, and here we pass new user object. Perfect. Now let's test this implementation. Save the changes, and let's send the post request. See, here we get new user with its unique ID. And if we check our database, refresh the database, here we get Cardwish. Inside this, we get users, and here we get our first user. What if we send the same request with same user info? See, here we get user already exist with error, 400 bad request. Perfect. 95. Hashing the password for security: Now currently in our usage data, we are storing password in simple string. But what if someone gets access to our database, then anyone can see user's actual passwords. To solve this issue, we can has the password in some random string, which makes our password unreadable. For hasing the password, we use one very popular library called BcryPt. NPM install BCRP. Don't worry about it. It is really simple. We will understand password hasing in separate file, and at the end, we will add it in our user's route. Here, we create a new file called pass dots. Good. Now, first of all, we import const, Bcrypt is equal to require Bcrpt. Now Bcrptespecially strong because it had SLD. You might ask what is sold? SALT is an extra piece of random data added to a password before it's has. Let me explain you in simple words. Let's say we have two users, user A and user B and both choose password. Let's say one, two, three, four, five. Now suppose our BRp package has this password which might look like this. If we just has one, two, three, four, five, without any salt, user A and user B has password. Look the same in the database. This is a problem because it's say these both users have the same password. If hackers see identical heed password, then they might guess that both user have the same plain password. So we need SLT to solve this issue. SALT is nothing, just random data, added to a password before hesing. So before userAPassword, we add some random data, so it's password look like this. For user B password, we add some random data or sold. So it's password look like this. It's not necessary, Bcrypt keep the same as password. I just show you for understanding. Let me show you that practically. Here we can use crypt dot and this function except two arguments. First one is the original password, which is the password entered by user. For example, here we pass one, two, three, four, five, and the second argument is sold round. This control the cost of hasing. High value means more security but slower hesing. Usually, a value of ten is considered secure and reasonably fast. Now at the third parameter, see, here we have to pass callback function because this is asynchronous operation. But instead of using callback, we can use here awight at the beginning. For using a weight, we have to write this expression with a sync function called a pass. And we simply move this line into this function. Now store that invariable called st pass and simply console dot log this st pass. Now, let's call this same function two times so we can see password at similar or SALT is working. Open up terminal and simply run node spass dot js. See, here we get two different st password. Even if we pass the same password one, two, three, four, five, for a, this is the power of SLT. Let's implement this code in our user's route. Cut this line from here and paste it before our new user variable. Now let's do some little changes here. First, we change this hard coded password one, two, three, 45 with our password, which we get from the request body. This will generate password for that user. At the place of saving the original password, we store this st password. Also, we have to import Bcrt at the top. Const Bcrypt is equal to require BCR. Sears the changes and take a look. In our database, we have used data without hasing. So we can delete this record from here, delete it. Now let's run our application using normon index dot js. Good. Now again, send the post request with the same data. See, now we successfully has the password and stored it in our database. Even if someone entered in our database, they can't see the password as it is. 96. User input validation using Joi: Now currently, our user route is working fine. Weg user is already registered or not, and also we are using the password, but there is a rule for the Bend developers. We as a Bend developer, never trust the data sent by client. We have to always validate that data. Suppose at the place of name, client pass, user name property. Also, sometimes they forgot to send email or even password. At that time, we can't store half information in our database. Now you might say we already set up validation in our schema. Should we have to add one more validation, yes it's often a good idea to add multiple layers of validation beyond what's set up in the schema. We will perform backend data validation in this lesson. This is another layer of the validation. If Acker somehow bypass this validation layer, then we already have validation in schema which will prevent invalid data from entering in our database. Here we have two options. Can perform manually or we can use very popular package called Joy. Also, we have other validators like Express validator, Yup and validator dot js. You can use whatever you want to. I love Joy because it's versatile and easy to use and A it integrates well with many nodejs frameworks, especially express dot js. Let me show you that. Open up terminal and write NPM, install Joy ethert 17.13 0.3. Good. Now to use joy is very simple. First of all, we will import joy in this file. So const joy with J is equal to require joy. You already know why we write here J because this joy package returns a class. Now with joy, we have to define schema for request body data. In this joy schema, and do many things, same as we've done in the user schema. We define here new variable called user schema or create user schema is equal to, and here we pass joy dot Object and inside this, we pass our schema object. In this object, we pass our fields with Joy schema. What is the type of properties? Is it required? What is the mean value, max value or mean string length ortring length, and much, much more? First of all, we need name to joy here, we can specify the type of field which is string. Make sure we call this function here. Now we can also add here mean to three characters, and also we want this filled to required. There are lots of methods joy. You can see all methods by using its documentation. Next, we have here email fill joy dot string. Now for email joy, we have email method, this also validate email and also pin this fill as required. Next, we have password to joy dot string dot Min 26 letter of password, and we also need this required. Last will, we want to validate his delivery address to joy dot dot Min to Pi and required. Good. Here we have this Joy schema now we want to apply this schema on the data which we are getting in this request dot body. That's why we write the same fields name as we pass in the request dot body. To validate the data using Joy, we have to use this creative users schema dot validate method. Inside this, we have to pass which data we want to validate and what we want to validate, request dot body. Now, this will return object we store in the variable called Joe validation. Let me show you what we get in this Joy validation variable. I comment out this bottom code and just validate this request dot body here and simply return response dot json, Joy validation. Say this in Js and take a look. Send the post request. See here our data is validate. That's why we get the value filled. If I remove this password from request dot body and send the Again. See, here we get error object and in that we have these details, which is array, and in that we get error message. Password is required. By using this error object, we can return error in our response. Don't get confused. Let me show you that. Remove this response dot JSN method. We don't need it and we simply write here I condition and check if joy validation error is available, then we simply return error in the response. Return Response dot status, 400 for bad request dot Json, and here we return Joy validation dot error Object. Now as a good practice, developers don't pass full error object from here. They like to send only error message. We add dot details, which is the array and we access its first element by square brackets, zero index dot MessagE let's test this, send the request without password filled. See, here we get password is required. If we pass password filled again, so undo, but in name, we pass only two characters. And send the request. See, here we get nice error message. Name length must be at least three characters long. In Mongo schema validation, we don't get these type of error messages, and that's why developers like joy. Now here, I have one question. If we don't pass here two fails, what we will get. So remove these first two fills. Send the request. See, here we get only one error. Joey run validation line by line. If first line don't get validate, then it will immediately return error. That's why we return always details first element dot message. That's how we validate input data which we get from the request body. You can remove comment from other code. God. To quick recap, there are three layers of validation in real world, client side validation, which front end developers perform on browser. Users can see that on front end form. Next, we have Bacon side validation, which we done just now using joy. In this, we are validating data, which we are getting from front end in request dot body. Next, we have Mongo schema, which is the final validation. Will prevent invalid data entering in the database. If someone pass client side validation, then we have wagon side validation, and if someone pass that also, then Mangus schema is always there. Adding these layers provides a robust approach to preventing invalid data for entering our database and it ensure a secure and reliable application. Now you can see we are working as a professional. Now in the next lesson, we will see how user authentication works in the real world. 97. How authentication works: Now let's talk about user authentication in node js. User authentication plays very important role in any application. I nodejs, we do authentication using JWT, or we can say it JSN webTken. Now you might ask, what is this JWT or JSN webTken? Don't worry about that. It is really simple. JSON web token is a long token string, which looks like this. By using this token, which we will generate in the back end, by that, we can authenticate user. Let me explain you with example how authentication works before JWT and how it works now. Here is a Harley he log in with his account information, email and password. Now our server first check the information, and if it is true, then server returns its user ID as response and store that in the session or ooki. Now, whenever he sends requests for some secured information, let's say, all his bank information. So server first ask for the user ID, and if he has user ID, and then server sends the secure information. But here is a one big problem, the SSN or Cookie in which we store our user ID, it can be easily modified in the browser. Let's say I change this user ID to someone else user ID, then we get the information about that user. This approach is not secured. Now to solve this issue, we introduce JSN web token. Now Harley again login with his email and password. Now our server first check the information, and if it is true, then server returns the long encrypted unique token as a response and store that in the local storage. Now, the great thing about this token is it is made with usage details and one secret key which only we will define on the server. No one knows the secret key except you and your team. So whenever Harley sends request for some secured information, then in the server, we first ask for the JWT token and verify it using our secret key. If it is verified, then and then from the server, we will send that secured information. And if we change anything in user information, then our token will also change. As a Bend developer, our job to send JSN web token when users sign up or login and also verify the token when we need. Storing the token in the local storage and everything else is a job of front end developer. Set a sum, when users successfully login or register, we send JSON web token, which simply works as security card. When user request for data which is only accessible by log in user, then server first check the security card, which is our JSON web token and validate it with the JWT secret key. That token verified, only then server returns the data to that user. Simple as that. Now in the next lesson, we will generate JCN web token and send it in response. 98. Generate the JWT token for user: So we understand JN web token. It is like a security card. Now let's generate a token when user successfully registered and send a token in the response. So for generating JSN web token, we need package of JSN web token, open up terminal and write NPM, install JSN web token. And if you want to install the same verson as mine, then write at the rate 9.0 0.2, and hit Enter. Good. Now in our user's file at the top, we import that package using require and simply store it in variable called JWT. Now when we want to create this token, at the very beginning or at last, we want to create token when our user data stored successfully. After this same method, we write JWT dot Sign In the sign method, we have to pass two arguments. At first, we have to pass data which we want to send within the token. For now, we want to just send user ID with our token. Object and first property, underscore ID to nwuser underscore ID. Make sure you write here, underscore ID. I have done this mistake before. Also, I want to send the name property of this user name tonuser dot N. Now at the second argument, we have to pass string, which is our security key. For now, we pass GWT, security key. We can pass any string. There are no rules for the key. Also, currently we are passing this key directly. But in the next lesson, we will add it in the environment variable. Don't worry about that. Now, this will generate JSN web token, so we store it in variable called token. Simply at the place of sending new user data, we pass only token. Let me show you how this token looks. Save the changes and from the Thunder client, we send new user data, write the full name, and change the email to code one@gmail.com. Make sure you addhe comma and send the request. See, here we get this long token, which we just generated. Now, let me show you more about this token. So copy this JWT token. Make sure you don't copy these double codes. Open a tab in your browser and search jwt dot IO. And this is the official documentation of JWT. Here in the libraries, you can see JWT implementation for different different libraries. Now back to main page and scroll down to Debugger section. And here we can decode our token. Now, let's understand what token contains. So past our token here. Now all GWT tokens divided into three parts. First part is about header, which is in the red color. Second part is about payload, which is in the purple and last and most important part is signature, which is in the blue color. Now, this header contains the algorithm and token type, which is very common. Focus on that. Next, this payload contains the data which we want to pass with the token. In this case, we pass user ID and use a name, which is this object in this sign method. The reason we pass here this data is we can display that data on our front end without calling separate API. After that, we have one more property It, which stands for issued at and its value is time when our token is generated. By this, we can see how old our token is. The last part, which is in the blue is signature, and it is generated based on our header, this payload data, and the secret key which is only available on our server. So this will prevent users from getting their own token and then modify it with ID to pretend to be someone else. Because if you modify anything in this payload or header, then the signature will regenerate. So there are no chance for users to do something unethical. By only this secret key our token will validate. Otherwise, it will give us error. That's why JWT is so popular. To quickly sum up, when users successfully login or register, we get JCN web token which simply works as security card. When user request for data which is only accessible by logN users, then server first check the security card, which is our JCN web token and validate it with JWT secret key. The two verified, only then server returns the data to that user, simple as set. 99. Setting Expiry of Token: Many developers as a good practice, set an expiry time for this JSON web token, like 2 hours or 24 hours. After that time, this token will not valid. If user want new token, then they have to login again. So for that, we can pass third argument in this JWT Sign method, Object, and in that we have property called expires in. We can pass values in milliseconds, if we want to set 2 hours, then write two for 2 hours into 60 for minutes because 1 hour has 60 minutes into again, 60 because 1 minute has 60 seconds and into 1,000 for converting seconds into milliseconds. You can see this is a little bit confusing. So we can also pass here in string to edge, which is 2 hours. Or we can write here one day for one day. Ever you like. A numeric value is interpreted as a milliseconds count. If you use a string, be sure you provide the time units like days, hours, et cetera. Otherwise, milliseconds unit is used by default. So if we only pass here 120 in string, then it equals to 120 milliseconds. I like to set 2 hours, so two edge, this expiry time is really depends on your application. You might notice in the banking applications, your login get expired in very last time, like five to 10 minutes. After that, you have to login again. The reason they use expiry Time for token is because they want to secure their application. On the other side, many social media websites set expiry time to 30 days or 60 days. Once you login, they don't expire your token because they want us to use more of their social media. Expiry time depends on your project. Choose best for your application. Just make sure you don't get annoyed by ExpiryT. 100. Secure the Security key in Enviroment: Currently, we pass our JWT secret key directly here. But in the real world, this is not secure because when we deploy our application on Internet, we also upload our code on some cloud like Github or Gitlab. If we write our secret key in this code, everyone can see our secret key, and this is not secure. So at the place of defining secret key here, we can edit in the dot ENV file. In this project, we didn't create dot ENV file. Create a new file here called dot ENV. In this file, we simply define variable called JWT underscore key is equal to, here we will write our key, which is JWT security key. Also, many developers like to adhere random key name so no one can predict the security key. You can use any security key, just to keep the backup of that security key. Now to access this JWT underscore key variable in our project, we need to configure Dot NV and which package we use for that, we need dotnV package, open up terminal and simply NPM install Dot ENV. Good. Now in the index dot js file at the very top, we add require dot NV and we call here dot config method. Save this file, and in the user's route here at the place of this hardcod string, we add process dot nw dot our variable name, which is JWT underscore Key. And done. Now, if we need to use this key again, we don't have to write the original key. We can write process dot E and w dot JWT underscore key. Now in the next lesson, we will create login route in which we will authenticate, email and password. 101. Exercise Create Login route: Now it is time for little exercise. You have to create a new API for login, so it should be a post request with endpoint API slash login. And in the body of this request, user can pass two properties, email and its password. So first of all, in this API, you have to find user by its email. If you don't found user, then you have to send error in response with message invalid credentials, and if user is available, then you have to compare password. Just these two steps. Don't worry about comparing the password, leave the exercise from that point. Just define new API and find the user with email. After completing the exercise, you can watch the solution. So I hope you solve this exercise or at least you try to solve that. Give yourself credit for that. Now let's see the solution. First of all, at the bottom, we define a new API using router dot post. Here at the first position, we pass endpoint slash login. At the second position, we pass callback function with two parameters, request and response, and adhere arrow function. Now let me show you my trig for writing code without confusion. I like to write steps in comman. For example, here, first step is find user from database by email. If we found user, then after that, compare encrypted password. If password is matched, then we create JSON web token and send it in response. By this way, we get the clear path for writing the code. First step, we have to find user by email. For that, we have to get data from the request dot body. Cost data is equal to request dot body. Or we can also destructure our object here. So at the place of data, we add object and we access our properties, email and password. Now using this email, we find user. So Const user is equal to here we have to await user dot Fine one here we pass comparison object and we compare email filled with our email variable, same as we done previously. Here, we get runtime error for using a weight. We have to make our function async. Good. Now we can check condition. If user is not defined, then we return here error. Response dot status 401 for invalid credentials, and also we send GSN Object with message property invalid credentials. Now, what if user is found? Yes, we have to check password is messed or not, but here is one thing. We store user password in encrypted format. We can't compare it directly with simple string password. So here we have to again use crypt package. So crypt dot compare the first position, we pass password, which we get from the request dot body, and after that, we have to pass a password, which we stored in database. So user dot password. Now, this expression again take little time, so we can await here and simply store that result in variable valid password. We can again pass condition if valid password is not available and we return the same error with same error message. I paste this line here. Now you might ask why we send the same error message? It is because for security reason, if we specify password not match, then it means we found user and just password is not matching. That's why developers send this type of error message invalid credentials. Now if password is matched, then we have to create a new token. I copy the code from the register API and paste it in our login API. Just we to do little changes. Here in the data, we have to pass user dot underscore ID and user dot name. At the end, we simply send response dot Json this token. Good. Now let's taste this implementation. So go to Thunder client and in the user's collection, create a new request and give it a name, log in a user. Change the method to post, and URL to STP, call a double forward slash Localhost 3,000 slash API slash users slash Login. And in the body, we pass Object with email fill. Here, we pass email, which we didn't create code 12 athergmil.com. Also pass password 12345678 and send the request. See, here we get error message invalid credentials. Now if we write valid email and pass the wrong password and send the request, see, we still get the same error. Now if we pass write email and write password and send the request, see, now we get JSON Web Token. That's how we create Login API. Simply, we have to find user, compare its password with BCR package. If it matched, then we generate JSN WebTken and send it in response, simple as that. Now, before moving forward, here we literally copy and pasting the code for generating the JSON web token. Just we change this data. It's better we create a separate function for generating the token, and then we can use it in both APIs. So at the bottom, we create a new function called generate token is equal to arrow function. Now from this function, we want to simply return token. Copy this JWT dot Sine method and paste it here. Now here we just want to pass different data. We replace this data object with data variable and we get this data from the parameter. Also, if you want to set different token expiry time, then you can also pass parameter for that. For now, we don't want that 2 hours is okay for both. Now in the log in API, we got this data object, which we pass in the JWT dot sign method and we simply call here, generate token function, and pass that same data object as argument. Good. Now, same we do in register API, cut the data object, and here we call generate to confunction and pass here that data object. By this implementation, our code looks more organized. 102. How to Authenticate User? Logged in or Not?: So in the previous lesson, we see after sign up and log in, we generate JWT token and send it in the response. Now let me tell you what front end will do with that token. So when we send JWT token from back end to front end, front end will store that token in the local storage of the browser or in the session. By that, front end will know user is logged in or not. When user want to access secure data, which is only accessed by login user, front end needs to send that token with the API call. So there are many ways to send token with the API call. But most commonly, front end will send token in the request, specifically in authorization header. If your front end use another method, then they will contact backend and then to implement it that way. So front end set the token in the authorization header. And when user wants to access protected API, which is only accessed by locked in user, then in the back end, first, which token is verified or not. If it is verified, then we allow user to access that API, and if token is not verified, then we return error with Status code 401, authorization token required. Now, where we write this logic? And create a middleware, especially for verify the token, and we can add that middleware for all protected APIs. Let me show you that practically. So in our project for defining a middleware, we create a new folder called middleware, and inside this folder, we create a new file called oth dot gs. Now, do you remember is middleware? Middleware is a function that either call the next middleware function or send a response to the current request. So here we define a function called Orth middleware and AV know for express middleware, we get three parameters request response, and next error function. Now, first of all, here we have to get the authorization header, SeconOth header is equal to request dot headers dot authorization. Make sure you write the correct spelling of the properties. Otherwise, we don't get the header here. Let's console dot log this auth header to just see what we are getting in this variable. In the future, we can remove this console. Also, in the real world, we get this outh header as this in the string, we first get error space, and then we get full JWT token. The reason we get here this error is because it is common authentication standard and ensure the server processes the token correctly. Now before we verify the token, we have to check whether we get token or not in this header. We adhere if condition, if O header is not available, or we adhere one more condition, oth header starts with here in string, we pass bearer space. If this condition is not true, then we return error. Make sure you add here not true. Now inside this, we return response dot status 401 for unauthorized request dot Jason, and here we send object with message property, authorization, token required. Make sure you send the object with the same property for every error. It will make easy to handle error on front end. Now, what at the oth header. As we know Oh header is a string with prefix, bearer, space, and then token. So we have to get token from this string. It is really simple. Const token is equal to oth header. Here, we use split method, and from where we want to split right from the space. So we pass double codes and space. Now, this split method will return array like this. First element is bearer and second element is our token. We can access token by index one. I square bracket, we write one. Now we have to only check this token is valid or not. So for that, we need JWT package at the top, we write Cast JWT is equal to require Json web token. At the bottom, we write JWT dot verify this method except two parameters. First one is a token which we want to verify, which is this token. At the second parameter, we have to add the JWT secret key, which is process Env dot JWT, underscore key. Now if our token is verified successfully, here we get the user data which we send with the token. We can store it in variable called decoded user. We can save this user data as request dot user is equal to decoded user. If in any protected route, we want to get the current logged in users data, then we can simply access it by using request dot user. Don't worry, I will show you that also as we move forward in this project. Now after setting the user data in request dot user, we don't want to do anything in this method. So we can simply call the next function, which we call the next middleware in the call stack. If we don't call this next function, then express will not call the API function or another middleware function. Our server will stay at this point, and that will make our server really slow. Always call next function at the end of middleware function. Now here in this code, what if our user is not verified? What if user passed a fake token or expired token? We also need to handle that. For handle error, we add here try and catch blog and simply add these three lines in the Try Blog. If we get error in these three lines, this catch blog will run. In this catch blog, we can simply return response with status 400 for invalid request dot Json and What we pass here. Right, we pass here object with property message and error message will be invalid token and done. We complete the authentication middleware. Let's also taste this. First of all, we have to export this orddalware to use this middleware in our routes. So module dot Exports. Equal to Auth middleware. Save the changes and head over to users route. Here at the bottom, after the login route, we add Router dot Get method and point to only forward slash. After that, we add callback function with request and response. This is the normal API. But how can we make this API protected, which means only locked in users should access this API route. For that, we have to add middleware before this callback function. At the top, we import const middleware. You can also call it OT is equal to require we go one fuller up, middleware OT. To run this middleware before this API callback function, we have to add it here before the callback function. When users send Get request to this endpoint, first, this orth middleware function will run. In that middleware, which act token is valid or not. If it is valid, only then we call the next function, which will run this API callback function. If in our application, we want to create any protected API, we have to only add Omddalware before that API callback function. Simple as that. Can you tell me how can we get the logged in users data? Right, we get the logged in users data from request dot user. So cost user equals to request dot user. And here we simply send this user in the response dot json method. Now let's test this implementation. Save the changes and first, we need to generate token. Open Thunder client and go to Login API. Here we have the data, so we can simply send this login request. Good. Here we get the token. Make sure you generate the letters token because we set 2 hours of expiry time. Copy this token, and here we create a new request. Give it a name, logged in user. First of all, we write the API endpoint, which is HTP, Callan double forward slash local host, 3,000 API slash user. Now send this request. See, here we get the error. Authorization token required because we didn't pass the token in the authorization header. So for passing the authorization header, we go to headers. Here we add a new header, key to authorization. See, we also get authorization, and here what we will pass. Yes, we have to pass token, but with prefix, error space, and here we passed a token. Make sure you don't pass it with double codes. Now let's send the request. See, here we get the log in users data with ID name, It which is the issued at, this is the time when this token is generated and EXP is the expiration time, which means when this token will expire. Also, if we check our terminal, a Console the auth header. See, first we get bearer prefix, and then we get token. So that's how we will add authentication middleware to make our API protected. So here we are getting only user name and ID. Let's send all information about the logged in user. So in the user's route, here we add Fine query, sconcTUser is equal to await user dot find By ID. And here we pass our user ID, which is request dot user dot underscore ID. Dot select, and here we don't want to send password. I string minus password, and then we return response dot jacon this user. Remove this first user line, we don't need it. Also, we have to make this function an. Save the changes and take a. See, now we get the full logged in users data. Now we can use this route for getting the full information of current log in user. That's how the authenticate user is logged in or not by using this Os middleware function. 103. OAuth in Details: So in the previous videos, we seen how we sign up and log in users using email and password, which is very important. But nowadays, you might have seen many websites provide some additional features, like we can sign in with Google, sign in with Facebook, Twitter, sign in with Github, and list goes on and on depending on the website type. Many users like to use these methods for signing. If they use these methods, they don't need to create a new password for another website and remember it. They simply use their Google ID some social ID and login into our website. Also, it is really secure. So it is very useful that we add these features in our application as well. But before adding them, you might ask how these features works behind the scenes. So here is the full architecture of the signing process. Don't get afraid. Listen it as just a story because in our daily life, we already using these features. Suppose here is a Hali he used one website called Amazon or Ebay. That website, he has option for signing or sign up with Google. If you click on this button, this button redirect him to login page of Google. Here he enter his Google email and password and log in. If he enter write email and password, then something happens on the web page, and at the end, he logs in in the Amazon or eBay website with his username email without creating the new password. This is really amazing. Now the main part is happening between these. Let me tell you what happened there. When Harley enter, write email and password on the Google account and hit Login, Google server generate a temporary code and send this temporary code our backend. Now, in the backend, using this code, we can fetch some usage details which we want to access and store it in our database, like name of the user, email ID, et cetera. So our backend will again contact to the Google server and tell them we want to access usage data instead of this temporary code. So Google server verify the code and extract the user data from that code. And then Google server send this usage data to the backend. In our back end, we have this usage data and we can use that data whatever way we want to use. Like we can store user name and user email in our database and generate a new user, or if user email is already available, we don't do anything and simply redirect user to front end with token. Now, when I first time learn about this architecture, which is the Oath or we can call open authorization. The time, I have one question and I'm sure you have the same question. Why Google server send first this temporary or authorization code to our backend? Why it can't directly send the user information? There are some reasons why Google server send this authorization code. Suppose Google directly send user information like email or profile data to the front end, then it can be stopped or deleted by hackers and also tempered or misused before reaching to our backend. Also the temporary code act like a permission sleep. It tells Google this user has logged in and given permission to our app. Only our back end with a secret key can extend this code for the user's real data. This secret key is given us by Google, and it will only available in our back end inVFle same as our JWT secret key. For the security reason, Google sends first, only temporary or authorization code. Here is the recap of how OAuth works. User first click on, sign in or sign up with Google button and then redcurs to the Google Login page, or we can say Google server. Now, after that, Google server, check the email and password is right or not. If it is right, then Google generate authorization code and send it to backend. Backend again send the authorization code with the secret key to Google server, and Google server extract the user's data like name, email, profile pig, et cetera. Now, at last in the back end, we can store that data in our database, or if user is already available, then we can simply redirect user to front end homepage with JWT Token. Simple as that. So this architecture will work for all type of social networks like sign in with Facebook, sign in with Github, Twitter, et cetera. Not only for Google. I use here Google as example. If we need Facebook, then this Google server changed by Facebook authorizes and server or Github authorizes and server. Now in the next lesson, we will practically implement this Oath in our Catwis application. 104. OAuth in Node Application - Signin with google: Let's implement sign in with Google feature in this application. And for that, we need one package called passpod dot js. So in OT Architecture, when user click on sign in with Google Pattern, we will redirect user to Suppose Local host Column 3,000 slash APIs OT slash Google page. This is our backend API. How can we define? We want to show Google Login page or link Google server with this page. Also, if on the back end, we get authorization code, how can we send requests to Google server and retrieve user data? Yes, we can do this all manually, but passport Js Library makes it so much easier. We will use it. Don't get confused. Just see this full lesson and you will get how this Oath implementation is working. So we go to passports.org page. Here we can see passport is authentication middleware for No Jz, extremely flexible and modular. At the bottom, we get all strategies like Facebook, Twitter, Google, Github, et cetera. Don't worry, simply go to the search bar and search here, Google, and select this passport Google Oth two. Make sure you don't select this oath 20. We use Oth two. These two are very similar, but this Oath 20 is older strategy. It is not really well maintained. So we will use this OR two, which has new features and it is actively maintained by passport. Let me zoom in a little bit. Yeah. So first of all, we need to install this package. So copy this command back to Vas code, open terminal, and in that terminal, we simply past the command here. And for the same version, you can write at the rate 0.2 0.0. And also, we need passport package at the rate, 0.7 0.0, and hit Enter. Good. Now back to documentation. Here they give us complete code for implementing passport with Google strategy. Copy this whole code, and in our backend, we can paste this code in our index dot Gs file. But Detw messed up our index dot js file, so we can store that code in the separate file. For that, we create a new folder called Config and inside it, create a new file, passport dot JS and page that code inside this. For now, don't worry about this code. I will explain this code and we will also do some changes later. Now back to documentation, scroll down, and here we can see they give us to get APIs to add in our application. First API is Auth Google and at the place of callback function, it passes passport dot authenticate method, and at the first position, they pass Google, which is the authenticate server, and after that, they pass the scope of the data. Basically, they are saying which user data we want to get from the server. We want email and profile, which include many details about user. Now you might ask what this API will do. When user send get request from the browser on this Oth slash Google endpoint, this passport dot authenticate method will open Google Login page. To add this route in our application, we can do something like this. In the route folder, we create a new file auth dot js. Creating separate routes for authentication. In this, first of all, we need Cost Express is equal to require Express. For adding route, we add cost Router is equal to express dot Router. Now, from the documentation, we copy this first route and paste it in the oth route. Also at the top, we have to input passport because here you are using passport. Const passport is equal to require passport. Now at the place of this app dot GAD, what do we use? Right, we use router dot GAD. Also, we don't add this OT. We will mention slash OT as prefix, same as we define prefix for users route. Now at the bottom, we have to export this route. So module dot exports is equal to router. Save this and before we forget to add this route in the index dot js file, let's add it. After this user's route, we add app.us. Here we add prefix API OT. At the second parameter, we have to pass Auth routes. So we input cost Os routes is equal to require. Here we go in routes folder OT. Now we simply pass these other routes in this app due method. Now back to auth dot js file. Here we have specified user Xs API Auth slash Google, it should open Google Login page. Now, after users successfully login, then what we want to do we need to specify that also. Reemember previously, we had some strategy code in the passport dot JS file. Understand this code, and also we will do some changes in this code. First of all, at the top, we need passport from the passport library because we are using it here. SeconctPassport is equal to require passport and also change this r to cost. After that, we have passport dot ug and inside this, we have new Google strategy, which we get from passport, Google author to package. By this strategy, we don't need to write manual code for fetching authorization code and extract data from the Google server. This strategy do all these for us. After that, we have object with bunch of properties like client ID and client secret. You will get this ID when you register your app with Google Console, and with that, we also get client secret code. Without these two fills, Google will not give us users data. So let's generate this too. Again, I'm telling you, don't worry about this code. When we complete this implementation, I will show you full workflow of this code. In the browser, search, Google Cloud Console. Open this second link. Here, we have to login with our Google account. You can use any account. Now, after login, it looks like this. Don't worry, simply go to here Select Project and create a new project. Give it a name. Let's say Card Wish and click on Create. Here in the notification, it is creating and select this project. When we select this project, we can see that project here. Now we need API and services. Click on these three lines and in the API and services, we go to O OT content screen. Simply do as I do and you are ready to go. Click on this Get Started button. Here, we have to do some configuration setting. First of all, here we have to write app name. Again, we write Cartwish. After that, select your support email and click on Save. Now here we have to select the type of audience, select here external. By that any user can login in our application and click on next. Here we write our email on which we want to get notification related to this app and click on next at last, accurate terms and continue and create app. Now we go to data access from the left side bar. Here, we have to select the scope of user data. Scopes express the permission you request users to authorize for your app and allow your project to access specific types of private users data from their Google account. Simply click on add or remove scopes. Select the first to email and profile and click on Update and save this. Now go to this audience, and here we can add taste users. Sometimes if after all implementation, our users can't log in, then it might be we have to add them in the taste users. When I did this, I didn't found any error. So don't worry about that. Simply go to clients. Here, we have to generate OO credentials, and for that, we click on Create Client. Select the application type to web application. Name, we don't need to change. But at the bottom, we have to add authorized redirect URIs. A redirect URI is the endpoint in our back end application where Google redirects the user after they login successfully. Here, we write STP, Column double forward slash local host, Column 3,000 API OT, Google, slash callback. Remember this endpoint. We need to define this API in our back end. And click on Create and done. See, here we get client ID and also client secret. Copy this client ID and in our application at the place of this Google client ID, we can page that ID or to make it secure, we can put it in dot ENV file. I think that is more secure. What do you think? So in dot ENV file at new variable, Google, underscore, client underscore ID. Equals to make sure don't addere space and past here client ID of your Google application. After that, copy this client secret, back to VSCode, and simply adhere Google, underscore, client, underscore secret. Equals to base here secret. Save this file and back to passport dot js file. Here, we pass process dot and dot Google, underscore client underscore ID. And here we pass process dot n dot Google, underscore client, underscore secret. Now after that, we have callback URL property. Make sure here we write the same endpoint which we pass in our Google Console App. We can see that from here, click on this edit button, and here we have callback URL. Copy this and paste it in double codes. At the end, don't touch this pass request to callback property. Make sure it is set to true. It will pass the request object to this callback URL. Now, after this, at the second parameter, we have callback function, or we can say strategy callback function. This function will run when users successfully login with their details, and we get here request object, access token, which is a token issued by Google to our app. It allows our app to make authorized request to Google APIs on behalf of the user. After that, we have refresh token, which is a token that can be used to get a new access token when the current one expires. Don't worry, we don't need this for now. After that, we have profile, which is an object with information about the authenticate user like name, email, Google ID, et cetera. Get this data from Google, and it really depends on the scopes we requested. And at the end, we have done, which is the function that you call when you complete process of user's data. Now inside this function, we don't want to find user or create a new user. We will do all of that in this callback API. So here we remove this code and simply reten here this done method. At the first argument, we pass error which is null. At the second argument, we have to pass users data. In this case, we can directly pass profile. To summarize, when users successfully logged in with Google, the strategic callback will run and in this profile, we get users data from the Google. Now when we call this done method with a null and user data to profile, passport will run this API endpoint, and we will define that endpoint in the next lesson. 105. OAuth with JWT: Now let's define this last step of the Google authentication, which is adding this callback API. Where we add this API, we will define it in the routes shorthtjsFle. Here we already add one API, which is step one. Now we add here another router dot Get method, endpoint slash Google slash callback. You have to give it the same as you pass in the callback property. So as we know, Google will send usage data on this callback route, and for that, we have to again adhere passport Middleware. Passport dot authenticate. Here we pass Google at the second argument, we set object with property, which is SSN to false. This will tell Passport library to not store user ID in the session. And also we pass one more property, failure, redirect, and when user data will fail, then here, Google server will redirect our user. So here we have to pass our front end URL. Here, for example, we pass Local React app. You can write SDTP column, double forward slash Local host. C5173 slash Login. This is very important. Now, after that, we can add our callback function, which we will run after we send profile data from the password strategy callback from here. Now, how can we get data in this callback? So we get data in the request dot user, and let's store this invariable called profile and simply return this profile object in the response dot Json and pass profile. Now let's test this is working or not. For testing this implementation, we have to send Get request to the endpoint. Open Browser and head over to SGTP Column double forward slash. Local host, Column 3,000. If your application is running on another pod, then you have to write your Bean URL here, and then slash API OT slash Google. And here we get error. It is saying error and non authentication strategy, Google. Let me check. Google strategy is correct. Also, we pass the right name of the ENV variables. Let me double check that. Yes, they are same. Oh, wait. We didn't add this passport dot js file in our index dot s file, and because of that, this file didn't config in our application. I think this is the reason we are getting that error. So go to index dot Gs file, and at the top, we add require, we go to Config folder and passport. See the changes, and let's restart our application. Mon index dot js. Now back to Browser and I rest the page, see, we directly redirect to the Google Login page. Here we can see our application name, which we mentioned in our Google Console. Good. Now, you have to write your Google account details and simply login with that. Here it asks for your permission for allowing Google to send your email and profile data to this application. Continue, and here you can see we get the user profile data object. At the top, we get provider, which is Google ID, which is the Google Unique ID. Display name to your name, email underscore verified to true so we get EML ID and many more details. You can use any of these details and store it into your database. So we have completed our major work for the Google authentication. Now we just need to check if user with this EML ID is already available in our application or not. It is not available, then we create a new user with its email name, Google ID, but we leave the password fill because for login with Google or Facebook, we don't need password fill, and then we generate JWT token for that user's data. If user is already available in our database, then don't worry, we simply update its Google ID in our database and then generate JWT token for that user's data. So to implement this, we need to change our users Schema little bit. How to do these changes because in our application, we have user who can log in with email and password, and also some user can login with Google. Let's first modify the schema of user. Here we make password, required to true. But as we know, when user login with Google, we don't store password, so we have to change required to false. Also, when we create a new user using Google Login, then we also don't store the delivery address. So we can also make required to false for the address and also remove this mean length property. After that, we can add one more field for user who used Google for login. We add Google ID type to string and unique to True. You might ask why we need this Google ID in our database? We need this Google ID because using that, we can identify user is already available in our database or not. But here, we have already users email. Why can't we use that email? See, in the browser, we are getting these profile details. Here we have emails property, which is the array of emails. One Google account has one or more emails like hurled gmail.com, which is the primary mail, hurleredcorporate.com for work email, et cetera. If Harley change its primary mail, then for the same Google account, we might create a new user account. For removing this email risk, we store Google ID. Another reason here we have to use Google ID is because someone can change their email address of Google account, but they can't change the Google ID. Google ID is unique for all Google users, and that's why we store users Google ID. Also, Google ID is for identify only that users who log in using Google, not for users who created account using simple email and password. For those we use email for identify. Save this file and let's quickly write our logic in this Google Callback route. Me write comment for this logic. First we check user is available or not using its Google ID or with email. If user is available, then we update its Google ID field and then simply generate JWT token and send it in the response. Here we don't need to verify password because user is logged in with Google. I user is not available, then we create a new user with name, email, Google ID, and then generate JWT token and send it in response. At the end, we have to send JWT token to front end, simple as that. First of all, which user is available or not. For that, we need users collection. So at the top, cost user equals to require, we go one folder up models users. Now at the bottom, we write fine query, user dot Fine one. And here we pass Object and we add condition, Google ID. To profile dot ID. Also, what if someone first login with email and password and then try to login with Google. At the time, we don't found that users Google ID in our database. So we need to also find user based on email. You can use here or operator. We add dollar or column, and we have to add here array of multiple condition. So we add one condition object, Google ID to profile dot ID, and second condition Object, email, to profile dot email. Now here is one thing. This profile dot email field will not 100% available. For some Google accounts, it works, and for few accounts, it will not work. So as a good practice, developer don't use this profile dot email field. They use profile dot emails, which is the array and we access its first element by square bracket zero index, and for value, we adhere dot value. As we know, this query returns a promise, so we can adhere await, in store the user object in variable, let user. Also, for using await, we have to make this callback acing. Now here we have two scenario. If user is available, and else user does not available. Now what we want to do if user is available, we will check Google ID is stored or not. I user Google ID is not available, then we set user dot Google ID. Equals to profile dot ID. This profile dot ID is Google ID. And after that, for saving aid, we write await user dot save. Now in the else, we have to write logic for user does not exist. Basically, we will create a new user. So we write user is equal to new user. Here we pass object with properties. First one is name to profile, dot display name. Then email to profile dot emails. Here, we access first element dot value. Same as we did before. Last property, we need Google ID to profile dot ID. For saving this new user, we write here await user dot save. You need to do only one thing. Generate JWT token and send it. So cost token equals to, we go to the user's route. We copy this JWT sign method for generating token and paste it here. Here at the pace of this data variable, we have to pass data which we want to send inside the token. And what we have passed in login, yes, we pass ID and name only. So here we also pass underscore ID, not Google ID. Google ID is just for backend for checking this condition. Simply copy this data object and pass here. If you want to send email also, then you can also menton that. But it's important in all token, you send the same details. It will easy for front end to use that data. Also make sure here we have to import JWT. Cost JWT is equal to require JSON web token. Now at the place of sending these profile details in response, we send JWT token, sems we send token in the simple signup and login with email and password. Also, sometimes front end developers tell you to redirect user at direct homepage of the front end. At that time we can do something like this. Response dot RediC and here we use template string. Here, we have to mention our front end page URL on which we want to redirect user after successfully login with Google. F locally, we can write SDDP, Column double for slash local host, Column 5173, which is DeitRact app. Here you have to write your front end URL, slash dashboard. Here we pass token in query parameter using question mark, token is equal to dollar Cali brackets, token. You can also change this URL as you want. It really depends on your front end. Many developers redirect users, and some developers send only token. I show you both way, you can choose whatever your front end developer tells you. Finally, we have implemented the sign in with Google feature in our application. Let's recap what we have done in last two lessons. First of all, user click on the sign in with Google Button. Our front end will redirect user to Local host Column 3,000 slash API Ath slash Google. This is our Bend URL. If your back end is running on local host 8,000, then user should redirect to local host 8,000 API Auth Google. Now, when user redirect to API Auth Google, this code will run. Here we mention passport dot authenticate with Google and mention the scope. Now, after that, directly this code will run, which is available in the passport JS file. Here, passport send our client ID, client secret, and the callback URL where we want to send profile data. After users successfully login with Google account and allow the permission, then this function will run, and here we return the method with error null and profile data. This profile data, we can access as request dot user in our callback function. Also, make sure here we unable pass request to callback to True. After that, our callback API will run, and here we write our user logic, and then we send or redirect user with token. Simple as that. I'm sure your all doubts are clear. Don't worry, this is your first time and because of that, you are a little confused. But with time, you will understand this without any confusion. Last two lessons a little long, but just see what you have implemented in your application. Congratulations for that, you can take little break from the screen and then continue this section. 106. Sign in with Facebook using OAuth: So previously, we added sign in with Google. Now we can also add sign in with Presbook or any other platform like Github or Twitter. There are some common steps we have to follow. Step number one, install passport and passport strategy library in node application. Step two, add first API endpoint, which will trigger passport with that strategy. Step number three, add passport strategy code in the passport dot js file. Same as we add Google strategy. Step number four, generate ID and secret for that platform. Last, step number five, define Callback API, store users data if needed, and send JWT Token. With these five steps, we can add any platform in OT. Let me quickly show you how we can implement the sign in with Facebook. Step number one, we have to install passport strategy. We go to the passport documentation and search here Facebook. See, here we get installation command, copy this and simply paste it in our terminal. Also, if you want to use the same version as I am using, then you can add here at the rate 3.0 0.0 and hit Enter. Now step Number two, we have to add API and point, which will open Facebook login page. So in the passport documentation, scroll down. And here we get API code. See, it looks very similar to Google API. Remember, and simply copy this first API. And in our th dot js file, after this callback API, we simply paste it here. Hang this API point to slash Facebook and also passport dot authenticate with Facebook, and for scope, we have to write here public underscore profile and email. Step number three, we have to add passport strategy code for Facebook. So go to passport website again and copy this strategy code. Back to viscodeopen passport dot js file, and simply at the bottom, we paste this code. Now we have to do some correction. First of all, have to import Facebook strategy from the package. So duplicate this Google strategy line and simply change this variable name to Facebook strategy. Same as they use here, and we also change the package name to passport Facebook. Good. Now here, we have to add these fills Facebook ID and Facebook secret which is the step number four. For generating the app ID and app secret, we have to go to Facebook developers page. Mention all details on the password documentation for every platform. Don't worry about that. The new tab, search here, Facebook, developer, console and open this first link. Here, click on Login. I'm login with my account. Good. After login, we get here get started option. It will may ask you for the register and verify. Complete the basic steps, and then you will redirect to this apps page. Click on Create app. Here, we write our app name, which is Cardwis. This is the same details which we fill in the Google Console. Now add use cases, so we want to authenticate and request data from users with Facebook login. Se like this and click on next. Here, select, I don't want to connect business portfolio. You might don't get this option because recently, Facebook becomes strict about this. So sorry if you don't get the option here, but don't worry, write a code as I'm writing. In the future, you just have to add only Facebook app ID and app secret. Here, click on next and next and done go to Deskboard now here, we have to complete these steps. So Clikon customize adding a Facebook login button. Here, we had permission. Add email and public profile is already added. Now click on this quick start. Here, we select web right here, our front end URL. For now, just write here, STTP, Column double forward slash, Local host, Column 5173. In real world, you have to write your front end URL here and click on Save and continue. Click on next, click on next, click on next and done. Now simply go to app setting at the bottom and go to basic setting. Here we get ApiD and App Secret. Copy this APD and in our dot ENV file, we add another variable called Facebook, underscore app, underscore ID. Past the app ID. After that, we add another variable called Facebook underscore app, underscore secret is equal to back to browser, and here we click on show it may ask your Facebook password, write that and see here we can see the secret code. Copy that and simply paste it in ENV file. Save the file and back to passport dot JS file. Here, we at process.nw dot Facebook underscore app, underscore ID. And here we also process dot nwt Facebook underscore app underscore secret. Now, after that, we simply copy these two properties from the previous code, callb URL and also pass request to callback and page them here for Facebook. Just here, we have to change the callback URL to slash API Oath, slash Facebook callback. Also, we have to addhe one more property because Facebook is not like Google. Facebook don't send much data, so we have to specify property called profile fields to array, and in this array, add all fills name from Facebook. We add ID, which is the Facebook unique ID, and it is unique for every Facebook user, same as Google ID. Also, we pass emails for emails, name, display name. Comma picture dot Type, and in the parenthesis, large. This is for getting profile picture. Most of the application use this data. Now here for callback, we want to do the same as this Google strategy. So we simply copy this strategy callback and based it in Facebook strategy. Here, our step four is complete. Save this file. Now last step number five, we have to just define this callback route for the Facebook. Pens dot gs file. Here we can simply copy this Google callback and paste it at the bottom. Also at the top, I notice we have to change this app dot GAD to router dot gat. Good. First of all, we change the API and point to slash Facebook slash callback and also in passport dot Authenticate at the place of Google, we pass Facebook. Now in the API callback, we have to change this Google ID with Facebook ID. So we have to add another field in our users schema same as Google ID. Here, select Google ID and press Control plus T or Command plus and select all Google ID in this Facebook API. At the place of that, we add Facebook ID, and we don't need to change anything. Save the changes and don't forget to add Facebook ID field in the user schema. Open users dot gs file and simply duplicate the Google ID field and change its name to Facebook ID, and we are ready to go. Save the changes, less is this. Open Browser and go to local host, Column 3,000 slash API OT slash Facebook. See here we get app not active. This app is not accessible right now. The reason is in this app, we didn't add or verify the business. Recently, Facebook becomes strict about that, but this doesn't matter because we can see when we make this Get API with APIs Orth, slash Facebook, we are getting the Facebook page, which means by our end our API is working fine. Our main goal is we implement sign in with feature. If your client requires sign in with Facebook, you can use their business and verify your app. After that, this feature will work, same as our sign in with Google is working. So that's how we implement Auth for our backend application. It is really simple. We have to follow these five steps. 107. Simplifying the Code: Now as we know, in this both callback, our code is the same. Just we change the Google ID with Facebook ID. As a better practice, we can define a common reusable function which simply written token at the end. Let's cut this logic from et user till this token generation. At the bottom, we create a new function, const, handle, or oth callback is equal to arrow function. In the Gly brackets, we past this code, and at the end, we simply return token. Now, first of all, for using this Avid, we need to make this function async. Now what we want to change here? Here, we need this profile data, and also we need this property which we want to change, Google ID or Facebook ID. So we can pass here two parameters profile, which is the full profile data, and after that, provider ID. We can't add this provider ID because when we call this handle or callback function, we pass Google ID or Facebook ID as string, and we can't add here that string. It will not work. Simply, we can use here, square bracket, provider ID. Also, at the place of user dot Google ID, we can write user square brackets provider ID. This is the second way to accessing the value from object A here and also in the Else blog and done. Now in the Google Callback API, we call this handle orth callback function. And pass here profile at the first parameter, and for provider ID, what we will pass write, we pass here, string, Google ID. Make sure you write the same field name as you set in the user's schema. Now, this function will take some time to execute. So we can use here await and this function returns token. So we can store it in variable token. Let's do the same for Facebook callback. Copy this token line and in the Facebook callback from the let user till this token, we remove this and simply past here this function call. Here, don't forget to change this provider ID to Facebook ID. That's what we said, fill name? Yes, it is Facebook ID. See, now our code looks clean. Now in the next section, we'll create APIs for products card and user orders. This is really fun. 108. Problem with Single Token [UPDATE]: Now let's see how big companies like Google, Microsoft, and Netflix implement secure and seamless authentication, and this is how other production level applications also implement authentication. They use two types of JWT token, access token and refresh token. Don't worry about these big words. Let me explain to you this in very simple words. Currently, in our application, we created API for register, a new user, and then we create API for logging that user. Both these APIs, we are sending JWT token to front end and our front end will send that token in the request header with bearer prefix and using that header, we get user information in our oth middleware. Now there are two problems with this approach. First one is the token expiration problem. We set token expiration time for 2 hours after 2 hours, our user need to login again to get a new token. This is bad user experience because they have to log in again every time the token expires. Now you might say we can increase the expiration time, and by that, our user experience will be fixed. Yes, this is true, but in this way, there is another problem which is about security risk. Imagine for good user experience, we increase the expiration time to ten days. Now, if that JWT token gets stolen by someone else, then the attacker or hacker can use that token as we are using until the token expires. In this case, we have no way to log out or revoke the token. We have to only wait for token to expire. So as we can see, we can't increase the time of the expiration. Have to make this expiration time to 5 minutes or 10 minutes. Now, to make user experience great, first Google, come up with these two tokens concepts, which is access token and repress token and we will see how this concept works in the next lesson. 109. Access Token & Refresh Token Logic [UPDATE]: Now let's understand the concept of excess token and refresh token. So in the place of creating one token, we create two tokens in our register or login API. First token, we called it as excess token and second token, we called it as refresh token. These both are JWT tokens, same as we generated token at the end of our API. But the only difference is for excess token, we set expiration time as sort like 5 minutes or 10 minutes or max in hours for reference token, we set expiration time as long for example, for five days or two weeks like that, excess token and reference token, both are JWT tokens. We can generate them by using JWT dot sign method, but just their expiration time is different. Now you might ask what will make difference by creating two tokens separately. To make this simple me explain your full workflow so your all doubts will clear. Imagine this is front end and this is backend. User fill the login form like email and password and submit it. At the back end, we check the details and compare password. If information is correct, then previously, we are creating one token. In this approach, we create two tokens. One is excess token and second is refresh token. We give excess token expiration time to let's say 5 minutes and for refresh token, we give expiration time to five days. We store this refresh token in user's collection and then send these both tokens to front end. Our front end we set excess token in the global API header with better prefix, same as before. Now, if user excess protected API, then at the back end, we get excess token from the request header and we can send the data our user needs. Now imagine after 5 minutes, our access token get expired. Our user send the API request again. Here, our backend checks, this access token is valid or not. Here it is not valid, from the back end we send the response with 401 error in valid token. Now on the front end, developer will write code. When front end, get 401 error, developer will call another API for getting new access token. Let's say OT slash refresh. Now in this API, we can access the refresh token. But here, we have to verify if this refresh token is valid for this user or not. Remember, when we generate new access token and refresh token, we store the refresh token in the database. We can compare these two refresh tokens if they are matched, which means user is valid. At that time, we again generate a new access token, a new refresh token, update the refresh token in the user's collection, and same as before, send these both tokens to the front end. By this, user don't need to login again and again. When user don't have refresh token or when a token get expired, only then you need to login again. Simple as that. Now the question you might ask is, what if this access token gets stolen? With that, attacker can easily get access. Yes, that is possible, and that's why nowadays, front end developers are not storing excess token in the local storage. They store it in the apse like JavaScript variable or RXtate or Redux store. And even if somehow attacker still the excess token, we keep the excess token expiry time to very short. Now you might ask attackers can also still the refresh token. What about that? And also, it has long expiry. To solve this issue at the place of sending refrestocan to front end, we can set refrestocen in the SDTPOly cookie. Now, what is the SDTPOly cookie? An SDDPOly cookie is an special type of cookie that cannot be accessed by JavaScript running on the browser. This SDDP only Cookie can't access via our browser. Our browser can only send this cookie with the API call. But JavaScript on the page or running in the browser cannot read, modify, or delete a cookie, which makes our refresh token safe from attackers. Now you might ask this SDDPOly cookie is sent only our API calls, or it will send with any other API calls. This is really great question. SDDPOly Cookie has feature which we called as same site to street. We set property, same site to street, and by that, this SDDP only Cookie will only send to our backend domain APIs, not to someone else backend. That's why refers token is high in security because it can't access by JavaScript. Now let's recap this access token and refers token concept. When user register or login at the place of one token, we create two tokens. First one is excess token, which expiration time is sought, and second token is refresh token, which expiration time is long. We store the refresh token in the user's collection for that user, and then we send the excess token to front end we set refresh token in the SDDPOlyOki. Now, the great thing about SDTPOly Cookie is it cannot access by the browser JavaScript code. Friend and browser can only send that SDTP Cookie with SDDPRquest. This makes our refresh token more secure, and as we know, our access token is available in the application state, not in the local storage. So our boat tokens are secure, and that's how we can give our user better experience and better security. Simple as that. So we use access token for accessing the data from the back end and that's why we call it access token. Also we use refresh token for repressing our access token, and that's why we call it refresh token. This workflow is really important for your application, and many developers don't really know about this full workflow. But I'm sure now you know about it, which is really great. Now in the next lesson, we implement this logic in our code. It will be fun. 110. Implement Access Token & Refresh Token [UPDATE]: Now to implement excess token and refresh token approach, we need to do very little bid in our backend. First, when we register or login user, we need to generate two tokens and store refresh token in the user's collection. After that, we have to return excess token, same as we are sending it previously in the response. And then we have to ct refresh token in the SGDP only cookie, so our browser JavaScript can't access or refresh token. Don't worry, it is really simple. Let's do that. So here we created one function for generating token, and we are directly returning the token. So instead of generating single token, here we can generate two tokens. So first, we change this function name to generate tokens. And inside this at the place of this written, we store it in variable called access token. And after that, we duplicate this line and we want to generate refresh token, such as the variable name to refresh token, also, we need to change the expiry of excess token to 5 minutes and refresh token expiry to seven D for seven days. Also, in the refresh token, we don't want to send all the user's data which we want in the excess token. So here at the place of data, we simply add object with ID, column, and passier data dot underscore ID. Also, many developers like to use different secret key for access token and repress token for security reasons. Here also, we open dot ANV file, and here at the place of JWT key, we write access token, key. After that, we create variable for rephrase, token, key, and give you any key you like to add. Save this and in our users route, in our function, we change JWTk to excess token, K, and this JWTk to rephrase token, K. Great. Now, at the end of this function, we return object with two properties, excess token, access token or we can remove this access token and after that, we return refresh token to refresh token. Good. Now let's see what we have to do in the register, a new user API. At the bottom, we can see we call this generate token function and we pass here under square ID and name property. Here, as we know, we don't return single token from this function. We are returning object, so we can destructure this object here and get access token and refresh token. Now in the response, same as before, we return excess token. Also, some companies also send refresh token in the response, but we are not going to do that. We are implementing here production level code. So we will set this refresh token in the SDP only Cookie. For that, we write response dot Cookie. Make sure you at response dot Cookie before writing response dot send or response dot JsN because we can't set cookie after we send the response. If you write it after response dot json, you will get error. With the first parameter, we write our property name. Let's say refers token. After that, we pass refresh token. At the third parameter, we have to pass object with some important properties. First, we write SGDP only to true. This means JavaScript on the browser cannot read this cookie. After that, we add secure to true for ensuring the SDP as request. Now currently we are testing it for local STDP request and that's why we make it here false. But to remember we write here command change this secure to true for production. After that, we have same site to street. By that, we stop our cookie to go on another domain API call. But here, you have to make sure your frontend and backend should be on the same domain. For example, gobleu.com for front end and cola.com for backend. If your backend and front end are hosted on different domain, then we can set this setting to none, which means our Cookie can go to any domain. Here we want our browser, send Cookie only for our backend platform. For that, here we write domain property to our Bend domain like api dotben.com. By this property, only this domain will get this Cookie, not any other domain. Currently, we are running our back end on Local Host 3,000 and in the domain field, we can't add local host 3,000 because here we have to add only real domain. We comment out this property also and at last, we add MaxH to our repress token expiration time. Here we pass seven days, same as our refresh token expiry time. Seven into 24 hours into 60 minutes into 60 seconds into 1,000 milliseconds. This simply means after seven days, this STP only Cookie will also expire and remove and done. We set the refresh token for SDTPOly Cookie. Now we have to do the same for login API. So we copy this response dot Cooke method, and before this response dot Jason, we paste it. So here at the place of this token, we destructure object and get here excess token and repress token. Also change the function name to generate tokens, and here we return excess token in the response. Also, when we create refresh token, we have to stood that token in our users collection because using that only, we will know how refresh token is valid or not. First of all, in our users schema, at the end, we add refrescen two Carly brackets, type two string. Save this and back to users route. Here in the login route before sending excess token, we add user dot refresh token is equal to refresh token. And then we add a weight user dot s. Now here is one thing. Many developers like to store he has or encrypted refresh token in the database for extra security, and it is also good practice. So here also, we can do cost, new hed, refresh token is equal to await, crypt dot a, here, we pass refresh token and we set SALT to ten. Same as we are hezing the password, we are hezing the refresh token. Here at the place of refresh token, we store the new hesed refresh token. Also, copy these lines and in our register API, we paste it here. Also we have to change this to new user dot refresh token and await Nwuser dot CV. That's it. Let's check this is working or not. Save the changes, make sure our backend is running. Now, open up Postman, open the login API and send the request. See, here we get the new token, which is our access token. And if we see after this body tab, we get one Cookie. If we check that, see, here we get the Cookie name which is refresh token. So we get value, domain, path expires, STP only to true and secure to false, which is great. So we successfully set refresh token in the SDDPOlyGoGi. Now in the next lesson, we will create route in which our front end send this refresh token, we verify that token and then send them new access token. 111. Refresh Route for New Access Token [UPDATE]: Now, as we know, when our access token get expired, front end will send refresh token to our back end for getting new access token. But the question is on which endpoint, front end will send refresh token. We have to define that endpoint. So in the author route, at the end, we add outer dot post, endpoint to slash refresh and callback function with request and response. Also, this is not compulsory. We have to define route called refresh. It is just a common convention developers use. Now in this function, we need to do little things. First, we check refresh token is available in the cookie or not. So to access the cookie, we use request dot Cookies dot our Cookie name, which we set to repress token. Let me show you. See, this is our cookie name. Now we have to store this value in variable called user repress token. And after that, we simply add condition. If user repress token is not available, then we return response dot status 2401 dot JSON message property to no refresh token provided. Now what if we get a refresh token? Simply, we have to compare that refresh token with the token which we save in our user's collection. Now the question is how we know which user send this refresh token. For that, remember when we create a refresh token, at the time we pass here ID in the token. So by using this ID, we can pass the stored refresh token. For that, we write JWT dot Verify. First, we pass refresh token, after that, we have to pass the secret key which is process dotenv dot refresh token key. Make sure we add here refresh token key, not excess Tgenkey. Otherwise, a token will not verify. Now, this expression return the payload or we can say the data. So we store it in the variable called decoded user. Suppose this token is not valid. Someone changed something in this token, so this expression can return error. So we can adhere, try and catch blog and simply add this line into dr blog and in the cache blog, we get here error, and we simply return response, dot status 403, dot Jason and messet property to invalid, repress token. Now suppose we get decoded user from the token and now by using that, we have to find the stored user token. So cost user is equal to a weight, user dot find by ID, and pass here decoded user dot underscore ID. Here also we add condition. If user is not available, then we return response dot status, 404 dot Json and message to user not found. Also, here for using await, we have to add async for our callback. Good. Now, if user is available, then we just need to compare the token. Now, as we know, in our collection, we stored as token, so we need to compare it in the same way we are comparing our password. So for that, we write await, decrypt dot compare. First we pass user refresh token, which we get from the cookie, and then we want to compare it with user dot refresh token. This expression will return it is valid or not. So we store it in variable. Cost is valid. Also, make sure we import B crypt in this file. So at the top, we add cost. B crypt is equal to require here we add Wikip. Now back to our route. Here, after this, we need to pass her condition. I is valid is false, then we return response dot status 403 dot JsN and message to refresh token is not valid. And if token is valid, then we need to repeat exact same process which we are doing after login successful. We open Login API here after comparing password, C, we generate new access token and new refresh token, as the new refresh token, update user dot refresh token with new stoken then we set the refresh token in the cookie, and at the end, we return access token. We simply copy this code. And paste it in our repress route. Now here, first of all, we need this generate to Cs function. We can input our function from the user's route file, but for that, we need to change input in the index dot JS file. I don't want to confuse you for doing that, so we can simply copy this generate to C function from here and we simply paste it in the outhoute file, and that's it. Here, our refresh route implementation is done. Let's this API, save the changes and take a look. Open Postman, here we create a new request called refresh token method to post, and here we write our URL, STP, Column double for slash Local host, Column 3,000 slash APIs OT because it is in the Outhoute. Slash refresh. Now simply send the request. See, here we get error, cannot read properties of undefined. I think we are not getting ooky in the user refresh token. Let me try to console dot log. User repres token, save the changes, and send the request again. See, here we get the same error, and if we open our via code, see, we are not getting the refresh token in the console log, which means we are not getting the user refresh token in the cookie. The reason we are not getting cookie is because in Node js, we can't directly access Cookie, same as we can't directly access request body data. Remember, for accessing the request body data, to add Express dot JN middleware. For Cookie also, we need to add one middleware which will help us to get Cookie from request. So for that, we install another package Cookie parser, NPM install Cookie, das parser and hit enter. Good. Now, in our index dot Js file, first we input cost cookie parser is equal to require cookie parser. And then at the bottom, we add app dot ug, Cookie parser and call this function here. Without this Cookie parser function, we can't access Cookie in request dot cookies. Also, in our represe API, I notice this decoded user is grade out. It's because we define it with Cst in the dry blog and because of cost, this decoded user is only accessible in this dry blog. Here we want to access decoded user outside of the dri blog. So for that, before this Tyblog we define let decoded user and then remove this cost. Now we can access decoded user here, save the changes, and take a look. Send the request and see here we get user not found, which means we are not getting user data. Let me check. Here we are passing decoded user dot underscore ID. Let me check it is underscore ID property or not. Yes, see, in the generating refresh token, we pass ID property not underscore ID. So we update this to underscore ID and also with the same the user's route generate tokens function. Save the changes and take a look. Here, if you get token expired, then you can call the log in API that will set the new token to Koki. Now let's send the refresh request again. See now in response, we get our new excess token, and also new refresh token is set in the request cookie. If we again send the same request, then see here we get both new token. This is similar to our front end page get refreshed. If excess token get expired, then our front end, call this refresh API, and then our front end gets the new excess token and refresh token. 112. OAuth with two tokens [UPDATE]: Now, let's quickly update Oth code also because here we are also sending only one token. So as you can see, we are generating token inside this handle OT callback function. Now at the place of generating the token here, we can use our generate tokens function and pass here the same data as this. And now we get here const cli brackets, excess token, and refresh token. Now we don't need this token variable, and after that, we simply return object with excess token to excess token, or we can remove this and refresh token to refresh token. Now here we have one thing. Here, we already have user data. It's good. We save the refresh token in the user's data, so we don't need to send another data by query. So from the login user API, we copy these crypting code, and also save token in user dot Refresh Token. And paste this code in handle or callback function. Now in our Google Callback API, here we get object at the place of token and we destructure excess token and repress token. Now, before redirecting user to front end with token, we need to set refresh token in the SDP only cookie. So we go to the login API again and copy this response dot Cookie method and paste it in the Google Callback API. At last, we simply pass excess token at the place of togan now we do the same for Facebook callback API. Here, we get object with excess token and repress token and paste here, the same Goki. Then we simply change this token with excess token, and that's it. Now in the next lesson, we see what we have to do for logo the user. 113. Route for Logout a User [UPDATE]: Now, can you tell me what happened when user logged out? If we expire excess token from the front end, then in the SCTP only cookie, we have already refresh token which has long expiry. Our front end can run refresh API again and get the new tokens, but we don't want that. We want to completely log out the user. So for that, we have to only remove refresh token from the SDDP only Cookie and from the user's collection. So let's create here new route, outer dot post slash Log hut and ASN callback function with request and response. Now for removing Cookie, we use response dot clear Cookie method. Here we pass our cookie name which we want to remove. We pass here refresh token, make sure you check your cookie name while you generate it. Now, this method will remove refrestken cookie, and it works in the local tasting. But when we want to implement this in production, then we have to also add object with properties. This expression work for production, but sometimes it can cause problem in the production. It's better we pass properties. Make sure it is the same properties as we add during Cookie creation. Copy this object and in our clear cookie, we pass it. Good. Now after that, we simply return response dot Json Object with message property logged out successfully. Now before removing the cookie, it's better. We also remove the refresh token from the user's collection. For that, we need to refresh token from the cookie, decode the user ID from the token, fetches the token from the database, and then we have to remove it. We have already done this in our refresh API. Remember, we can simply copy this code from getting Cookie to decode user until we are getting the user. Copy this and simply paste it before the clear Cookie method. Now here we have user. We just need to do user dot refresh token is equal to null. And then we await user dot save and done. Let's test this logout API. Say the changes NO one Postman, duplicate this refresh token request. Good, change the request name to logo a user. Change API and point to slash logout. Now, currently, we check our cookie. See it is available here. Now, if we send this logout request, see, here we get logout successfully, and if we again check the cookie, it is gone from here. So this is how production level registration, login, logout and token works. Also, last six lessons are updated lessons. So if you don't see this code in upcoming lessons, then don't worry about it. You can follow those lessons. I just want to make these sores up to date. So currently we are tasting this project. So if we set excess to an expiry to 5 minutes, then it is very hard to taste. So for tasting only, we set expiry to one day. Also, in the user's route file at the bottom, we change excess to an expiry to one day. In production, we can update it to 5 minutes. 114. Section 10 - Creating the Category Model: Welcome to the then section of the ultimate Node JS course. In this section, we will continue working on our project two Ecommerce Application backend. We will add some cool features like adding products images in backend, role based authorization, simple and fast search query, and much, much more. So let's start into this section. First of all, in our ecommerce application, we want to add products by category. If you select category earphones, we will only send products whose category is earphone. For that, we have to define category model. So in the models folder, we create a new file called category dot JS. Now, inside this file, first of all, Const Mongoose is equal to require Mongoose. After that, cost category schema is equal to nu mangos dot schema. Inside this object, we will add our schema. Now, what do you want to add in this category collection? First, we need the name of the category. Then we might need the icon of the category. These properties depends on the UI part of the front end. We want to display categories like this with icons, then we have to store that Cn file name in our database. Now, in our application, we want to do one thing. Only Admin can add categories in our database. Simple user can't add category or delete category. A, if in our application, we have multiple admins, then we can add here filled for Admin. Is the ID of that admine. But here we don't want to store the admin details so we can remove this fill. So we have only two fills for this category model or collection. So we add here name to object, type, to string required to true and also unique to true. Next, we want icon image name to object, type, to string because we want to store the image name here and required to true, and that's it. Now many students get confused in storing image in the backend. Let me explain you the logic. In database, we can't directly store images. So we do something like this. Suppose user upload this one image from the front end. In the backend server, we create one folder called uploads, and in that we store the image. Now we have uploaded file in our server with whatever name we want to give to that image. After that, we simply store the name of the image in the database. Also, some people like to store whole path of the image, but that is not needed in this case, because we are storing this image on our own server. So we need only to fill name of the category and image which is the image name. Now, after that, we can create a model based on this schema. Seconst category is equal to Mongos dot model. First, we pass the singular name of our categories collection, which is category. And second, we pass the schema, and at the end, we module dot exports is equal to this category. Done. Now in the next lesson, we will add API for creating new category with image upload. 115. Create a new Category API with Image upload: Now let's create a new API for category. For that, we create a new file in the Routes folder called category dot js. In this file, what we do? Write, we have to create Router using Express. So const Express is equal to require Express. And next const Router is equal to express dot Router. And also at the last, we have to export this router. Module dot exports is equal to router. Good. Now before we forget to add this new route in the index dot JS file, let's do this. I have done this mistake and tried to test my APIs. Save this file, go to index dot js file. Here, we import category routes is equal to require here we go to the routes folder and in that category. Now at the bottom, we use app dot g. Here, we define the prefix, which is API slash category. After that, at the second parameter, we pass category routes. Save this file and back to categories routes file. Good. Now let's define API for creating new category. Here we define a new route using router dot post. 8.2 forward slash, and here we pass callback function with request and response arrow function. Here we want to store the icon image with the name of category. So for storing the image, we need one package called Multer. This is very popular package for storing all types of files in the Express application. A lot of developers confused with Multer but it is really simple. Let me show you. Open up terminal and write NPM install Multer at the 1.4 0.5 dash ts dot one and hit Enter. Good, minimize this terminal. Now, in our file, we first add Const ulter is equal to require Multer. And after that, we create a variable called st upload is equal to here, we call this Multer method, and inside the parenthesis, we have to pass object with dest property, which is the destination. Here, we have to specify in which folder or path, we want to store our image. We write upload category. By this, our category images will stay in separate folder. Now we have to add this upload method as middleware of our post API. Here we add upload dot. Here we have many methods like single. This will accept only single file. None, this will not accept any file. A will accept multiple files. N will accept all files and fills, which accepts specific multiple fills. If you want to go more deep into these, then you can look at its documentation. For now, don't worry about that. Here, we want to accept and save only single file. We use here, single method. Now in this parenthesis, we have to pass the field name. Suppose we pass here, icon. Now from the front end, we have to use input tag, type to file, and in the name field have to pass the same name which is C. By this filled name, Malta knows which file it has to save, and that's it. Multer will save our file icon in the destination path upload category, and we will get the information about that file in the request dot file, and we will get rest of the form data in the request dot body, same as before. Now let's write the rest of the code for this API. So first of all, here we add I condition, and this will check request dot body dot name is not available or request dot file is not available. Then here we return response dot status, 400 for bad request dot JSON, and here we pass Object with message property and pass here error message, name and icon are required now what if we have this both? We create a new category, const, new category is equal to new. Here, we need category model. So at the top, cost category is equal to require here we go one folded Up models category. Good. Now at the bottom, we adhere new category, and here we pass object with properties of this collection. First, we add name to request dot body dot Name. We have only one fill in the body, and that's why we don't destructure this fill same as before. Next, we pass image to request dot file. And here we want to save the file name, so we write filename. If you want to store the full path of the fill, then you have to adhere, request dot file dot path. Also, we can adhere console dot log, request dot file to see what we get into request dot file, so we don't get confused. After that, we add await, new category dot c, and you know what we have to do now. Yes, we have to make this function is for using await, at the very end, we send response with stats to 01 for new data dot Json. Here we add object with messet property, category added successfully. As we pass category to new category. Now let's test this API. It is a little different because here we have to send file. We can't send a file in the JSON format, so we have to use here form, and also we can't upload file using Thunder Client because that feature is only available for paid user. Many developers like Postman and don't like Thunderclient because of this. We will use Postman here. If you don't know Postman, I will give you my previous tutorial for quick guide of the Postman. So to download the Postman, we go to postman.com. Here, we can download this application. Simply install this application. It is really simple. This is how it looks when we open it first time. We have two options, create a new account or log in with account. I quickly log in with my account here. If you sign up or log in, then you can create here collection just like Thunder client. Here, we create a new blank collection. Caris and in our Cartws project, we add a new folder called category. If you want to zoom in, then press Control and plus or Command Plus. In this folder, we add a new request, create a new category. Now, first of all, we select post method, URL to STP, column double forward slash local host, Column 3,000 ABI category. Now to send a file in the body, we go to the body. Here we select the form data. Here, we get key, which is the fill name, value, and description. For first, we add our key, which is the filled name to let's say laptops. Next, we enter our fill name for file, and what was that? Remember, we write here icon. So here also, we have to write icon. For upload file at the right side of the key, we get text and drop down, which is the content type. Here, we select File, click on Select File and select a new file from the local machine. Now for laptop icons, go to the resources folder, which you download previously, or you can also download it right now below this lesson. Resources folder, I added folder for Project two. In that folder, we go to category folder, and in that, you get all icons for category. Select laptop dot PNG file, and OpenI. Now let's send this request. Here I get error. Sorry, I forgot to start this application. So note on index dots good. Also, here I notice I make this mistake, response dot status. Save the changes and back to Postman and send the request. See, here we get the new category, laptops and image to this random name. Also, let's check our file get saved in the upload folder or not. See, here we get the file with that random file name. So it is working there are some issues. This file, save without its extension like dot png, or dot JPG, et cetera. Without extension, our image will not visible on the browser. This is the number one issue. Next issue is here, we can upload any type of file, not only images. Suppose by mistake, someone upload here dot PDF file, then what we will do. So here have to add filter for that also. Only dot png or dot jpg or dot GIF can be upload for this image fill, and we will solve these issues in the next lesson. 116. Set file name & filter in multer: The previous lesson, we have two issues. We don't get extension for our image file and also in database. Second, we can't filter only images. Let's solve this. This is really simple. Let me move this category above of the multer so we can see this clearly. Here, we pass only dest property in the multer function. But in multer, we have few more properties than desk. Remove this destination and here we can pass storage property, which except the multer disk storage property. So instead of cluttering the co here, we can define it in separate variable. Cost storage is equal to multer dot disk storage. Inside this, we can define how and where files should be stored on our server. We pass Object and first property is destination where we want to store our file. This except Callback function, which has three properties, request file. This is the uploaded file object, and CB is a callback function to specify the destination path. Error function here, we simply call this callback function at the first position, we pass null, which is for error. After that, we will pass our destination path, which is upload category. This callback will set the destination as upload category. If this directory does not exist, then we have to create it manually. But we have already this folder here. If you don't have, then you have to create this path, upload, and in that folder category folder. Otherwise, ulter will give us error. Now, after the destination, here we can also specify the file name property. This also accept the callback function with the same three properties, request file, CB for callback and arrow function. Now in this function, we want to define the specific and unique file name for our file. Unique file name because if two file names are same, then the last one will replace the first image. Instead of female picture, user will get male picture, and that's not we want, as a common practice, we store the timestamp in the file name like this. First timestamp, and then file name with extension. This are almost all files will get unique name. SecctTtmp is equal to date dot now. By this, we get the current time. After that, we want to also do something in the file name. SeconstOiginal name is equal to file. Dot original name. By this, we will get the original name of the uploaded file like laptops dot PNG. Now in the file name, there are maybe some space, so it's better we replace that space with the dash. It will make our file name URL friendly. We add plex method. Here, we first add regular expression and its syntax is double forward slash between these, we add backward slash as for space and plus for one or more white space. At the end of the regular expression, add G for global flag, which makes sure all matches in the string are replaced, not just first one. Here we pass dash in single codes, this means all space will replaced by dash. Now, what if in the file name, we also get the special characters? We need to remove them as well. We add another replace method. First, what do we pass? Regular expression, and what is the syntax, double forward slash? Between these, we are getting regular expression for getting the special characters. Here we add A to Z, Alt A to Z zero to nine, also now we want to get other characters which are not part of this, and that will be our special characters. T inverse this, we wrap it in the square brackets and after the first square bracket, we will add Garret at the end, we also add G for global flag. Now we want to replace these special characters by nothing. We just want to remove it. So we add here only codes without anything. Don't worry if you don't know much about regular expressions, it's okay. Now by these two methods, if our file name is this, then it will make like this. Now at the end, we will mix this timestamp and original file name. CB first we pass null for error, and second, we write back tags, here we add dollar Cully Brackets, timestamp, dollar Cully brackets, original name and done. We define destination and also file name for our uploaded file. Now we can simply pass this storage variable here in the Multi function. Our first issue is solved. Now we move to issue two for applying the filter for file. In the multer function, we have another property called file filter. Here also, we have to pass callback function so we can define it in separate variable. Cost, file filter is equal to callback function with three parameters, request, file, and CB error function, and in this function, we decide whether the file should be accepted or rejected. Here, we first define a variable, allowed types, which is the array, and here we add all types which we accept. First, images GPG, which is dot JPG and dot JPG both. Then image png, for dot png, and image GIF for dot GIF. Here, we can simply put condition. If While mime type is from this, then we allow it, else we will reject it. If allow types, dot includes and in the parenthesis, we pass file dot Mme type. Now you might ask what is Mme type? Mime type stands for multipurpose Internet Mail extensions type, which is a label used to identify the format of the file or data. Applications or browsers know how to handle it. If we upload PNG file, Mme type will be image slash PNG, or if we upload PDF file, then Mme type will be application slash PDF like this. If Mme type is available in the allowed type, then we call the CB function, and first, we pass null for error and pass through for except the file. Now, if M type is something else, then these types, then we adhere as condition and call Cb function, and at the error, we pass new error, and here we pass error message, invalid file type, only JPEG, PNG, and GIF are allowed. And to reject this file, we add here false. D. Now we have to add here, file filter to file filter. Here, we solve both issues. Let me show you one more useful property of ulter. Here in the multi function, we have limits which help us to limit the file size. Imagine someone bumstakally upload here 10 megabytes icon. We don't need 10 megabytes for small icon. We can limit its file size. Here we pass object file size. Here, we have to pass file size in bytes. For our category icon, we can set limit of two MB, that's more than enough, and to convert it into bytes, we add into 10 to four. By this, we will get kilobytes or KB and again into 104. By this, we will convert that KB in bytes. And done. Now let's test this API. So go to Postman and here we have already our data for laptops. Send this request. See here we don't get response. But if we check our uploads category folder, we get new file with our unique name. Extension, our image is storing. Now let's check the error and if we check our terminal, then here we can see we get duplicate key error for name laptops. Remember, in the previous lesson, we store the laptops category with that random file name and also in the category schema, we set name property to unique. We have to remove that previous category from Mongo Di B Compass. Here, simply remove this document. Also, we remove both images from our server. We don't need it. Now we again send the request. See, here we get success message. We get good image name and also image saved properly in our server. Great. Now let's add some more categories. So second category name is smartphones. And for that, we upload icon of mobilephone dot png. Make sure you remove first image. Otherwise, it will send to images. Send the request. Next, we have category, smart watches, and icon we select here watch dot png. And send it. Next, we have headphones and icon to headphone dot PNG and send the request. Last, we have gaming consoles and for icon videogame dot PNG and send it and done. Now in the next lesson, you will create API for getting all categories from our collection. 117. Getting all categories API: Let's create API for getting all categories. It is really simple. After the post API, we create a new API, router dot Gate forward slash for endpoint, callback function with request response, arrow function. And inside this function, first, we get all categories from the model. So C categories is equal to a weight, category dot find. And if you want to send category short by category name, then we add here shot method, and here we pass fill name by which we want to shot, which is name and simply send response dot JCN categories. Also, here we have to make this function acing. Save the changes, and let's taste this API. So go to the Postman or tender client. We add here new request. Yet all categories, in the endpoint, we write Local host 3,000 API category. Select the Get method and simply send the request. See, here we get categories shorted by their names. Pretty cool. Now if you need to add more APIs like update or delete the category, then you can also do that. It really depends on you for now we don't need it here, so I don't create them. 118. Sharing Static Images from the Server: Currently for categories data, we store the image in our upload slush category folder. But how can our browser access these images? They are available only in our server. For accessing the images from the browser, we have to share the static image files from our server. Have already done this in the Section five, Lesson four. It is really simple. So index dot js file here after express dot J and middleware, we add app dot U. Here we had the prefix of the static file path, so we set it to upload category. Now for sharing the static files from the server, we have to use another built in middleware called express dot static. And inside this function, we have to pass the folder name which we want to share. Upload less category. Just remember this is the prefix for URL, and this is the folder path of our static files. Save the changes, and let's try to access this laptop image. Copy this image full name. Now go to browser. Here in the URL, we write our backend, Local host, Column 3,000. Here we have to add the prefix for static file, which is upload slash category. We pass here images category, then we have to also write Images category in browser URL. For now, we stick to Upload category, and here also, we pass Upload category, and here we paste the full name of the image. See, here we get the image. That's how using this URL, front end will display these icons. Now in the next lesson, we will create a new model for products. This will be fun. 119. Exercise - Defining Products Model: Now it's time for little exercise. You have to define a product's model. In this model, we have the fills, and this is the sample data of single product. You have to design schema by your own for these fills, take your time, solve this exercise, and then what's the solution. I hope you solve this exercise or try to solve it. Give yourself credit for that. Now let's solve this exercise. For product model, we create a new file in the models folder called products dot js. Good. First of all, cost mangos is equal to require mangos. After that, we define cost product schema is equal to Nu Mongoose dot schema. Inside this, we pass object in which we define schema. First property is title, which we set to type to string, required to true, and also we adhere max length to hundred. Now next description which we want to set to type string required to true, and it's min length to 50 characters. After that, we need seller who list this product. Here, we store the seller ID, so object type to Mongoose dot schema dot Types dot Object ID, ref to user required to true. Now here you might ask why we don't use here hybrid approach? Why we don't embedded data for seller? Why we store seller ID. Here on the front end, our products card will look like this. In the list of products, we don't want to display the details of seller. If we want to display the seller information, here, then we can also add here, seller name, and some required details, but that is not the case here. You have to think like this when we want multiple data in single API call, multiple data means t products data in single API call. In that data, we need to display the reference data or not. If in that data, we want to show reference data, then it's better to embed that data in the collection. By that, our API don't need to run populate query for each embedded data. At that time, we can use hybrid approach. After that, we need category. Now tell me which approach we use here, embedded or reference. Right, we use your reference because we don't want to show category with multiple data. We just need category for filtering products. So we again, use your reference type to Mongos dot schema dot types dot ObjectId. Ref to category and required to true. Next, we have price. Here, we set type to number, required to true and mean to zero. Obvious. Next, we duplicate this line and change this price to stock, which is the number of products available in the stock. Next, we have images, which is the array, and in this also, we store image name as string. The reason we adde array because products can have multiple images. As we required images to true. This will make sure our product has at least one image. After that, we have last property reviews, which is the array of review object. Now this is interesting. In the reviews array, we want multiple reviews object. We have to define the schema for that object. Here we simply pass object, and in this, we can define schema for that object, same as we are doing previously. In this object, we want three information user who submit this review. So I object, we pass type, Mongos dot schema dot types dot Object ID, f to user and required to True. Next, for the review, we need rating, so it's type to number, and also we required to true and mean value to zero. At last, we need command, which can be string, but we don't add here required to true because not all users will add command. They just like to add stars. Now you might have question when we add a new product, is it compulsory? We need to add these reviews? Because here we pass require two. So the answer is no. We don't need to add reviews compulsory. This required for this single object. If we try to enter new review object, then it should have user ID and its rating. Otherwise, it will not need it. Basically, we are adding schema for that single object. Also, you might ask, can we embed users data here? Yes, we can embed data here, but imagine users change the user name, then it will really hard to stay consistent with that data and don't worry too much about designing the database. Almost all companies have team for designing the database, or some senior developer will design the database. I'm just explaining you why we use reference and why we don't use embedded approach. I think it will clear your doubts. Here, our schema is complete. Now we can create model from this. Cost product is equal to Mongoose dot model. Here we pass the singular name of our collection, which is product, and after that, we pass product schema, and at last, we export this model. So module exports is equal to product. 120. Role Based Authorization: Now let's build API for creating new product. In the Routes folder, we create a new file called products dot js. Now we have to create a new router using Express. SecstEpress is equal to require Express. Next, cost, Router is equal to express dot Router. Also at last, we have to export this router. Module dot exports is equal to router. Now, let's add this new router in the index dot js file. Save this file, go to index dot js file. Here, we import cost product routes is equal to require. We go to Routes folder and in that products. Now at the bottom, we add app dot g. Here, we define the prefix, which is API slash Products. And at the second parameter, we pass products out, save the changes, and back to our products routes file. Here we want to create an API for adding new product. So router dot post, API and point to forward slide. Here, we make sure only log in user can access this API. So we can add here Osmalware. See here I get auto suggestion, and also it will auto input Omdalware at the top. Now we add request response, and arrow function. Good. Now before we handle how to store products image, we have to check only sellers can add product, not simple users, only sellers, and how can we do that? We will use middleware. In the middleware folder, we create a new file called cheseller dot js. Now, as we know, middleware is a function. We define const, check seller is equal to request response, and next and arrow function. In this function, we have to check if the user rule is seller or not. If it is not seller, then we return error. I request dot user is not available, or request dot user dot role is not equals to seller, then we return response dot status, 403 for forbidden Xs dot JSON. And here we pass object with mesetPperty excess denied sellers only. If you surpass this condition, only then we can pass them to the next middleware or API callback. Now let's export this function from here. So module dot exports is equal to check seller. So the changes. Let's set this middleware after the orth middleware in our products API. See, again, auto input works. Great. Now, here are two things for you. First one is in our user schema, we only set two values option for role. Let me show you open users dot js file. Here we can see we have only user and admin. We need to also add here, seller, and save this file. Now the second thing is, how can we get user role in the request dot user dot role? Because in the request dot user, we get only those data which we pass while generating the token. Remember, we pass only two properties underscore ID and name. Let's see this also. W users dot js route here in the sinnup at the end, C, we only pass underscore ID and name. Here we have to also pass role. Roll to new user role. Good. Also in the login at the end, we also add here role and here we have to use user dot role because we already have user here. See the changes. Now what about Google and Facebook based authentication. There also we pass only underscore ID and name. We have to also pass the rule. Otherwise, our cellar meter ware will give them error. So pothjs file where we need to change here, we create this common function. That's nice. See, at the top, we are finding the user, so that's easy for us. Here at the bottom, we are generating the token, so we add here role to user dot role. And done. We made all changes here. Save the changes and let me close other files in the products API, we simply return here response dot SN seller is here. Let's test this API. First of all, let's add login API in Postman because I don't think for products also, we will use Tundar client. In our Cardwih collection, we add a new folder called users. And we add here request called login a user. First, we select and point to API user login. Make sure this method is set to post. Now for data, I simply copy it from the Thunder client back to Postman, select here body, raw and simply the data here and send the request. See, here I get fresh token, copy it and for tasting the products API, you will create a new folder in cartwdg called products. I think we have to permanently switch to the Postman. When I started research on the scores at the time File Upload feature is available in the free version of Tender client. But now what we can do, we switch to Postman. Sorry about this. Here we had request called create a new product. Select the endpoint to API slash products, request is post and send the request. See, here we get error, authorization token required. Sorry, we didn't pass token in the header, go to headers. Here we add authorization, and in the value, what we have to pass first we add error space and we paste our JWT token here. Now let's send this request. See, now we get another error message, access denied sellers only. So to quick recap, we add one middleware for seller after the Othmdalware because by orthomdalware, we get the user's data in request dot user. If token is verified and user rule is seller, then only the seller Moware function will allow us to enter in the product's API. This is how we can perform rule based authorization. To enter in this API, we have to make our current account to seller's account. So when Mongo Di become pass here in the user's collection, find your account by which you are login and change its rule to seller. Make sure seller, not sellers. Now we have to generate a press API token because we change our data. Send the login request copy this token back to products API. Here in the header, we replace the old token with Barrer space new token. Now let's send the request. See, here we get seller is here. Lovely. 121. Custom Role Based Authorization: Now previously, we added categories API. Here, we didn't check the role of the user for adding new category. Here also we want. Only Admin can add categories. So there are two options for us. We can create a new middleware, same as this check seller middleware, or we can create a new middleware which checks any role of the user. If in that middleware, we pass admin then it should only allow Admins. We pass seller, then it should only allow sellers. Both options are good. It really depends on you which you want to choose. Let me show you both. For Admin, we simply copy whole code from the check seller file, and in the middleware folder, we create a new file called check admin dot gs, and simply paste this code. Now here we have to do little changes. First, we change this function name. Select this and press F two and write check admin. After that, we have to change this condition, role to admin, and also in the error message admin only, and we are ready with our admin middleware. We can add this middleware in our API after the Osmalware same as we add check seller. Now let me show you how can we create general rule check or middleware. It is really simple. In the middleware folder, we create a new file called check role dot js. Here also, we can simply paste the same code and change this function name to check rule. Now you might ask, how can we pass rule in this function? Because as we know, at the place of middleware, we just have to add this function and that we'll call this callback function. Here we can do simply one thing. We can add here one more arrow function. So after equal sign, add role parameter and then arrow function. So before adding this arrow function, for accessing this request response callback, we have to call Jack rule function. Now, after adding this arrow function for accessing this request response callback, we have to call Jack rule function. Here, we pass the rule of the user, let's say admin. And after that, we simply call it one more time. And by that, we can access this request response callback. This is called higher order function. A higher order function is a function that returns another function or takes another function as argument. Here, we are returning this callback function in this check rule function. In simple syntax, it looks something like this. Here is the check rule function, and it simply return this callback function. That's why we call check rule first time, and then we have to call it again to access this return function. I hope it clear your doubts. Here, we can replace this seller string with rule parameter. And here, for custom error message, we convert these codes into back digs, and at the place of seller, we add dollar role and that's it. Now we can use this custom rule checker middleware with any type of role. So it really depends on you if you like to use check seller and check and mid middleware, or you like to use check rule middleware. I like to use this check rule middleware. In the products API at the place of check seller, we have to call check Rule middleware. And here we pass rule seller. This check rule seller is same as check seller middleware, both call this request response callback. Now for the categories also want to check role as admin. In the category route, we want to add middleware for this create new category route. Now here is one question. Why should we add check role middleware? Before this multer upload or after it? Right, we add it before this multer upload method because first we check the rule. If it is admin, then we will store the icon image in our server. We add Jack Roll middleware after the ulter method, then it will first store the image in our server and then check the role. So we add check roll middleware before this and pass here role admin. Also, before check Roll middleware, we have to add Auth middleware because without that, how can we get the user information in the request dot user? Save the changes and let's taste our products API. Send this request, and here I get error. Let me check. It is error in the check Role file. Oh, sorry, I forgot to remove this function call. See the changes, and let's send the request again. See, here we get seller is here. That means our middleware is working. So that's how we can use this check rule middleware for any type of rule based authorization. 122. Handling Multiple Images of Products: Before saving the actual products data in the database, let's create multi upload method for storing multiple products images. So here, seller can upload minimum one image or maximum eight or ten images. So from the categories route, I simply copy this storage file filter, and upload variables and paste it before our products API. Good. Now, first of all, we need to import Multar package. So cost ulter is equal to require multer. Also, we can remove this jag seller middleware import. We don't need it. Now here, we have to do little bit of changes. First, we change the destination to upload slash products. By that, we can make sure products images are separated from the category icon. And as we know, multer don't create directory by itself, so we need to create it. In the upload folder, we create a new folder called products. Here we will store our products image. These are small details which we need to keep in our mind while working with nod Jas, as you work more in nod Jaz, you will know all these things. Don't worry about that. Now, after that, file name is okay. File filter is also okay. If you want to also store videos, then we have to add these MM types in the allowed types array. For now, we don't want it, and also size limit is two MB, which is also okay. Here you might ask this two MB limit is for all images combined size. No, it is for each image size, not for combined size. Now let's add this upload method in this API. After jackrll middleware, add upload dot, we want to store multiple images, so we can use here array dot single is for single file, and dot array is for multiple files. Now here, we have to pass fil name for these images. Here, we set it to images. So from the front end, they have to send all products images in the single images filled. We will see that when we taste this API, now after passing the field name, we can pass the limit of the files. What are the maximum number of files we want to store? For ecommerce application, eight is more than enough, but you can also adjust this count by your needs. Also, if you don't want to set the maximum limit, then we don't need to pass the second parameter. But here we want eight image. Now, as we have seen, previously, we get the file information in the request dot file because there have single file. But here we are dealing with multiple files, so we will get this files data in the request dot files plural. By that, we will fetch each file name in database. Also, we can create here common ultter function, but that will create unnecessary confusion. That's why we leave it as it is. Now in the next lesson, we will store the products data in the database. 123. Create new Products: Let's store the product details in the database. So first of all, in this callback, we get all fields which we are going to pass in the request dot body. So cost CLI packets is equal to request dot body. Now, first of all, in this body, we get title, description, category, which is the category ID, price, and stock. Now after that, we have to create images array, which is the array of image names, and how can we get that? So we get all images details in the request dot files array, and each image data is available in the object like this. And here we get a file name. So we can do this. Cost images is equal to request dot files dot MAP. Here we get each image object arrow function and we simply return image dot file name. This filename is what we generated at the top. Now by this map method, we get the array of image names. Also, sometimes sellers forgot to add images. We can put here condition if images dot length is equal to zero. If it is true, then we simply return response dot status, 400 dot JSON. And here we pass error in object with messed property. At least one image is required. Now here we have all information. Let's quickly store this information in the products collection. Cost, new product is equal to new product. See, here we get authorization, products from model, good, and here we pass new product object. In this object, title to title, and as we know, if object property and value name both are same, then we can simply remove this. Both works the same. Next, description to description, category, price, stock, images. And now at last, we have to store the seller. How can we get that seller? Right, we can use request dot user dot underscore ID because our Osmitalware is setting the usage details in the request dot user. Let's count the fills to see if you are missing fills or not. One, two, three, four, five, six and seven. The product schema, also, we have one, two, three, four, five, six, seven, and 80s reviews, which we will not add now, so we are going on the right track. Now, let's save this data. Await new product dot c for using await, we have to make this function is now at the bottom, let's return response dot status to 01 dot GSN, and here we send new products data. Save the changes, less is this API. This is really exciting. In the resources folder, I added project to folder, and in that, you will get Products folder, and inside that, I added products images by category, and also you will get the data dot GSN file. In which I added title, description, and all other details. Open this data dot JSNFle in the VS code. See here I added category name at the top, and in the products array, I added all products data with title, description, price, stock, image is name, so you can search image by that. The reason why I don't add here category ID because for each category ID can be different because previously, we added category manually. Here is my smartphone category and here it's ID. You can compare it with your category ID. It can't be same. Copy this ID, go to Postman, here, first go to form data. Here, we simply add key category, and in value past the category ID of smartphones. Next, we have to add title, then description, price, and stock. I copy these all details one by one from the JSON file and paste them here. First, select title, paste it here, description. Price is 1299 and stock is eight. So pas the description, price 1299, which is USD and stock to eight. Now we need to add only images for this product. At the bottom, we add another key images. Here, we select type to file, and now we select our iPhone 14 images. So go to Products folder, smartphones, and we go to iPhone 14 Pro folder. Here, select all images 1-4. Now let's send this data. See, here we get this new products data. Here we have seller category, image names in array, and also in our back end in the upload products folder, we get these images. We did a great job. I am adding all these products details in my database. When we run the GD product query with pagination, then we get more data. You can also add all products in your database if you want to. Otherwise, you can simply skip this part. Now I copy the next product title, paste it here. Don't touch the category ID because we are still in the same category. Description. Paste it here and price is 399 and stock to 50. Now let's select images for Samsung a 54. Send this request. Good. Like this, you can add all products or at least ten products. Just change the category ID when you change the category of the product. I know this is boring, but we can use this data to taste our get products API. So put some chilling music and create these products. I am also doing this, see you in the next lesson. 124. Getting all Products Data: So in the previous lesson, we added products in the database. See, I added all 24 products in the database. Now let's get these products through API because that's how front ten will get this data. So after the post API, we add router dot Get and point to forward slash. Now here we don't add any middleware because we want any user can see all products, not only logged in users. So we directly add here final callback with request and response. Good. Now here, first we get all products, so const products is equal to products dot find. We don't pass here any condition because we want all products. And here we have to add await for the query. And for await, we add here async and at the end, simply return response dot JcNPducts. S the changes let's test this implementation. In the postman, we create a new request in products collection, G A products. Here, we enter the endpoint to APIs Products, select Method to G and simply send the request. See here we get all products data in array. And in that array, we get object for each product with all fields. Now my question is, do we need all details here? Can we reduce size of the data we are sending from the back end? If we hover over this size, we get the response size with header and body separate. Notice the current data size 14.39 KB. Now let me show you how our products page should look like in front end. See, here we have the list of all products, and it is almost similar to Amazon or any ecommerce application. If you pay attention to the products card, we don't really need all details. Let's write the fills which we want to display in the products card. First one is ID for identify title of the product price, stock if products is in a stock, only then we display head to card button. Next, of course, display image, which will be the first image from the images array. Next we need details about reviews, and that's all. In our query, we add select method for selecting the fills. Now, instead of adding all fills name, we can write which fills we don't want. For that, we just add or minus before that field name. We don't need description. Also, we don't want to display seller. Also not category, and we don't want underscore underscore V. It is not necessary. Here's the changes and take a look. Let's send the same request again and let's check the size. See, it is reduced by one third because description has more data than any other field, and that's why we remove unnecessary fills. Now let's make this data more narrow. Here we also don't want all images. We just want first image to display on the cover. Now there are two solutions for that. First one is we can create a separate fill in our products model like display image or cover image. When we are storing the new product, then in that field, we will store the first image name. That's one solution. Another solution is we can extract first image name from each product and add it in the same product object which we are sending from the back end. By this way, we don't have data duplication problem. See both solutions are great. Here, we can't apply the first solution because we added all products. I will show you the second solution, which is also great. First of all, here we write products dot Map. Now here we are getting single product object, and arrow function. Now as we know, whatever we return from this function, it will be the item of the new array. The logic is we will return all data which we have in single product, and then we don't want to send the images array, so we will replace that images property with the images first element. We want images array, when we don't add a new property with the same name, we can make it display image or something else, but here we don't want to send images array. That's why we are giving the same name. Let me show you. Here we return object. Inside this, first of all, we will add all properties from the single product wide spread operator. We add all properties of single product as it is. After that, for replacing the images property, we add here images and here as value, we set product dot Images, first element, which is index zero. Done. Now, this map method will return a new array with all updated single product object. We store it in variable called updated products. At the place of products, we simply return updated products in response dot JSO. Save the changes, and let's see we are getting this correctly or not. See, here we are getting some weird object and at the end of each object, we are getting this images property, which means our map method is working. But why we are getting this weird object. Let's simply const dot log this products array and Al in the response dot json, we again send products object. Save the changes, and let's send the request. See, here we get the regular products array and back to VS code, open terminal, and see here we are getting the same products array. Now let's try to move this console line in the map method. And at the place of products, we console dot log the single product. Save the changes, and let's send the request. A terminal, S, here we get again the regular single product object. I think when we are adding spread operator, that when we are getting that object properties, instead of single product, we wrap it in the object and add here spread operator. S the changes and send the request. Back to VSCode. See, here we are getting this weird object. What is happening here. So this happen when we are getting data with mangos, we don't get simple Javascript object. We get Mongoose document object, which includes both the raw document data in the dog and additional properties and methods like dollar underscore underscore, dollar is new provided by mongoose for managing the document. Now the problem is we don't want those properties and methods. Want simple JavaScript object from the database, not mangos document object. To solve this, we simply add an property at the end of this query. This removes all the extra mangos specific properties. Now we can return here updated products in the response. Save the changes and take a look. Send this request and see, here we replace images array with the first image name, and if we check our data size, reduce more. Lovely. That's how we debug and find the error. Now here is the one thing also. Here we are sending full reviews array in that we have object who has usage details, the rating, and also comment. Currently, for all products, we don't have any reviews. That's why we can't see that large data. Also on front end, we just want to show rating average and total number of rating. We can also replace the reviews array with only two properties. Let me show you. We remove this console. We don't need it. First of all, create a new variable cost number of reviews is equal to product dot rev dot LNT. Here, Jack, you have reviews or review. I have review, so I stick with product dot review. Now, how can we find average? Average is basically, we have to sum all rating numbers and divide it with total number of reviews. We define a new variable Cast sum of ratings is equal to now to sum the ratings, we use reduce, which is array method. Badu dot review, which is array dot reduce. Now here we get two parameters. First one is total, or we can say sum, and second one is current value, which is single review. And what do you want to do in this callback? Simply sum plus review dot reading. After that, in the second parameter, you can set the default value of this sum, which we set to zero. This reduced method will take two arguments. First one is callback function, which we use to do some mathematic operations, and second one is the default value of the sum parameter. Now we have sum of ratings, cost average rating is equal to sum of rating, divided by number of reviews. Now, here's one thing. If number of reviews are zero, then what? 0/0 will give us undefined. If number of reviews is zero, AsiR or operator one. This will prevent that error. Now let's replace review array by these two properties. After images, we return review to object, number of reviews, to number of reviews, or to simplify, we remove the second property, average rating to average rating. Save the changes and take a look. Send the request again and see now we can review as object. So from the query, we just send what front end needs. So that's how we have to think when we are sending data from the back end. 125. Pagination or Infinite Query: Now currently we are sending all 24 products from the database. Imagine if in our database, we have 100 or thousand products, then sending all products in single response will make our API slow. Tell me what should we do in this situation? Right, we can send data page by page, so our front end can implement pagination or infinite scrolling features. We have already seen this in Section seven. Let's implement pagination or infinite scrolling query. Backend is same for both features. First of all, we will get the current page number from the query parameter, and how can we access it? Right, by request dot query. Cost page is equal to request query dot page. Now, this request dot query dot page is string because whatever we get from the query parameter, it will be string. We have to convert this page into integer, we wrap it with parenthesis and parse integer. Next, we have to define how many number of products data we want to send in one page. So const per page is equal to eight. Now we have to simply add two methods in our query. First one is dot Skip and here we pass parenthesis page minus one per page. If page is one, then one minus one, zero into eight, which is also zero. Our query skip zero products. If page is two, then two minus one, which is one into eight, which is eight. So our query Skip first eight products. Now, after Skip, we have to add Limit property, and in that, we pass per page. So limit is how many data we want to fetch from the database. Simple as that. Let's test this implementation, send the request. See, we only get eight products. Now you might ask, we didn't pass page in the query parameter. Still we are getting eight products. Yes, we are getting eight products because this request dot query dot page is not defined. So the skip method will skip zero items, and then we set limit to eight. So that's why we are getting eight products. What if we want to make this query more customized for front end? Imagine our front end want to ascend per page products in query parameter. Suppose ten products on single page. We can do something like this. Instead of this hard coded Ed, we get request query dot perpge query parameter. Again, we convert it into integer using parse integer. Even if front end don't want to pass per page parameter, pass here default value, so operator eight. And we can handle this page by adding operator and default value will be one. See the changes, and let's get data of page two. So we question mark at the end of the URL for passing the query parameter. Page is equal to two. And also, we pass per page to ten and send the request. See, our query, skip first ten records and then send page two, which is 11 to 20 products. Now here is one thing. On the front end, many times they need more details like total number of products. By that, they will decide how many pages they have to display or how many times they can get the data from the back end. So they want current page number and some other details. Let's quickly get these details and pass them in the response. First of all, after these update products, we can do something like this. Cost, total products is equal to await product dot cow documents. This will count all products. Now after that, we can also count a total number of page, cost, total pages is equal to total products, divide by per page. Suppose we have 50 products and per page is eight, then we get 6.25, which means full six pages, and we need one more page for display two products. So it's better, we always seal this number. For that, we have to just wrap this equation with math dot SL function. This will convert this 6.25 to seven. Now at the place of sending this updated products array, we pass here object. First properties products to updated products, total products, to total products, or we can also remove this. Also, we pass total pages. Also, we can send page, which is current page to page and post per page per page. I added here all information, but you can add it according to your needs. Save the changes, and let's send the same request. See, we get products array and with that we get these details. That's all we have to do for pagination or infinite query. 126. Sending Products By Category: From getting products, we might want to get only products by category. For that, we don't need to create new API. We can simply implement that in this query also. First, we get the category name in the query parameter, cost query category is equal to request query dot category. If we don't pass category, then we pass here or null. Now, after that, for query, we add variable let query. We set it to empty object. Here, we pass this query object in this fine method. Now we can fill this query according to our needs. This query is the comparison object. We pass here if condition query category is available, then first have to add category property to category ID in this query object. Now, if from the front end, we directly get category ID, then we can directly pass that ID in the query object. But most of the time we get category name from the front end. We have to find category ID from our database. Cost category is equal to a weight category dot Fine Vn. Here we pass comparison object name to query category. Make sure we import this category model at the top. So cost category is equal to require. Here we go one folder up models category. Now, what if we don't fund the category? Here we check if category is not available. We simply return response with status code 404, not found in Jason method, pass object with message property, category, not found. The end, we simply set query category is equal to category dot underscore ID. Now our query object looks like this. If we pass that in our fine method, then it will act as comparison object. Now, let's test this from Mongoi become pass, go to category collection, copy any category. Suppose I copy the smartwatches category. Now back to Postman in the URL, we add another query parameter and category is equal to smart watches. Make sure you write the same name as we have in the categories collection and send this request. And here we get empty array. Oh, here we pass page is equal to two, and in this category, we don't have that much data which we can show up on the page too. So we change this page to one and send the request. See, here we get all watch products. 127. Sending Product By Search: In our application, user can also search the products and want to see all products according to their search. We can also implement that in this single query. It is not compulsory to add all features in this query, but I'm showing you the real world practice. After this category, cost query search is equal to request query dot SRG or we set it to Null. After this category condition, we add another if condition, query search is available then we set another property in the query object. Query dot title is equal to object. Here we add dollar jx, to query surge and to make this query case insensitive, we pass another property, dollar options to string I. Also, at the bottom, in this tutor products, we have to pass the query object in the count document method. I forgot to pass it in the previous lesson, and that's it. Save the changes and take a look. Add here another query parameter, and surge is equal to here we add app and send the request. See, we get only one data because in its title, it has Apple. That's how we can customize this Gtquery for getting all products. Also, I notice one thing. We successfully store our products images in our server folder, but we can't access it. We need to set those static files like we did for categories images. In the index dot js file, after this category static, we add app dot ug. Here, we add the prefix for the static file path. We pass uploads products. Now, after that, we use Express dot static Middleware for sharing the static files from the serfer and inside this function, we have to pass the folder name which we want to share. So uploads products. Remember, this is prefix for URL, and this is the folder path of our static files and done. 128. Exercise - Getting Single Product Data: Now when on the front end, someone clicks on the products card, we should show them all details about that single product. Here is the exercise for you. You have to define a new API for getting single product details. So our API should look like this. Slash API products, slash product ID. This ID, you have to find the product. Also, try to get seller actual data like seller's ID, seller's name and email ID, not simple seller ID. Try to solve it and if you forgot about populate, then you can watch six and seven populate lesson and then try to solve it. So I hope you solve this exercise or try to solve that. Don't worry if you get error or stuck at some point. It is the part of learning. I also used to stuck a lot where I learned node first time. Don't worry about that. Now let's see the solution. So we write router dot Gt. What do we pass in the URL? How can we know which product details we want? Right. Here we add column ID as root parameter, and this is the unique ID of single product. Now, again, we don't add here middleware because any user can see single product details. We directly pass callback function with request and response. First of all, we need this ID, so Const ID is equal to request dot VMs dot ID. Now by this ID, we can find this product. So C product is equal to await product dot find by ID. Here we pass product ID. Also we make this function async. After that, we can put condition I product is not available, then we return response with status code 404 dot JSNObject with message property, product, not found. Now, if we get the product from the database, then we simply response dot Json this product. Say the changes, and let's test this API. Copy this first product ID because we need it. In the postman, we create a new request called Get single product. Good, select the URL API product. And here we paste our product ID. Make sure the request is G and send the request. See, here we get the full single product data. Now if we pass here some random ID and send the request, then we don't get the data. And if we check our terminal, see our application got crashed. It happens because we don't handle error in our API. Don't worry, we will do that in the next section. Currently, we have to restart this application with node mod. Let's again pass original ID and send the request. Nice. Now here we have little issue. In the single products page, we want to show the seller's information like the name and email. But here we get seller ID, so we have to populate that data from the user's collection. Also, we don't want this category filled. Other things are okay. First of all, after fine method, we pass dot populate. At first parameter, we pass which field we want to populate. Right, it is seller, in which data we want to populate underscore ID, name email. Now, also, we want to populate the user, which will be available in the reviews array. Here we have to populate NASD data. It is also really simple. We pass another populate method. At first parameter, we add review, which is the array for accessing user, we have to write dot user. Now at the second parameter, we again want the same fills. Underscore ID, name and email. Good. Save the changes and take a look. Send the request. See, now we get Seller's Object with ID, name and email filled. Currently, we don't have reviews. That's why we can't see it. Also, we forgot to remove this category fill. At the end, we pass dot select Method and here minus category and minus underscore underscore ID. So the changes and take a look. Send this request, C, we remove category and underscore underscore V property. That's how simple node js is. At the beginning, you feel it is tough. But if you do step by step implementation, then you can master it properly. And that's why I explain you code line by line. Now in the next lesson, we will create API for deleting the single product. 129. Exercise. - Deleting the Product: Now let's create API for deleting the single product. So here we write router dot delete. Here, we again get ID as route parameter. Now here we need middleware or not. Right, we need middleware because only logged in user can delete the product, and also we want to get details about that user. First of all, we pass oath middleware. Then we pass API callback function with request and response. Now, first of all, we get product ID from the route parameter. Cost, product ID is equal to request dot params dot ID. Now we have to find the product from this ID. Cast product is equal to await product dot find by ID in that we pass product ID. Now from this query we only need seller's ID. Add select method, and here we pass sellers filled and also at the top, make this function acing. Now we put here condition for product is found or not. So we simply copy this condition from the previous API and paste it here. Good. Now if we found product, then we check user is admin or user is the seller of that product. We write I request dot user dot rule is equal to admin or request dot user, dot underscore ID is equal to product, dot seller. If any of this condition is true, then we can delete this product. Now the question is, how can we remove this product? In this product object, which we get from the database, Mongoose also pass one method with it, which is dot delete one. And that's it. By this, product will remove from the database. Also, we use here delete one method because previously we get the product from the database. If we have to directly remove that product, then we use find by ID and delete method. Also, we have to add here a wait because this is asynchronous operation. Now, after that, we simply return response dot Json with message property, product deleted successfully. Now currently, we comment out this delete logic to check this implementation. We will enable it after some time. Now, if this condition is not true, then we return here response with status code 403, 44 Biden dot Json with mesa property, excess denied. Only admin or seller can delete this product. Now let's taste this implementation, copy any product ID from our products list. I copy this last ID, now in the post win, create a new request called tilt, a product in this method to delete, here we write URL, API products, and here we pass our product ID and make sure method is delete and send the request. Oh sorry, we need to also send JWT token in header, go to Login API, login with your user data, who is the seller of that product. See, here I get JWT key, copy that, and in delete API, we go to headers and add here authorization in key. As value, we pass error, space, and paste JWT key here. Now, send the request. See, here we get access denied, so we don't get into this I condition. That's why we get this error. The problem is in this condition, let's simply consol dot log this booth condition. Copy this first condition and paste it here, comma, copy the second condition and paste it here. Say the changes, and again, send the request. Now back to VS code, opened a terminal here for the first condition, we get false, which is true because we are not admin. After that, for a second condition, we also get false. Why this account is seller of this product. Select separately consult dot log, these two properties. Remove this first condition, and at the place of equals, we add comma. See the changes, and let's again, send the same request back to VS code, and in the terminal, see, first we get object ID in string, and then we get new object ID, which is Mongoose object ID. That's why the string and object ID are not matching. So either we have to convert this both into object ID or we can convert this both into string. Both will work. So we convert these both into string. In JavaScript, we have dot two string method to convert data into string. Pass that dot two string for both IDs and remove this console. Save the changes, and let's send the request again. See, now we get product deleted successfully. Now, if you want, you can enable this delete one method. Now, after we delete the product from the database, it's better to also delete those products images from the server. For deleting the file from the server, we can use FS module. So at the top, Fs is equal to require Fs promises. And we also need path module. So const path is equal to require Path module. Now at the bottom, after this delete one method, we add fs unlin. Now in this method, we have to pass the full path of the file which we want to remove. But in the images array, we only have file name, but we need here full path. For that, we need to use Path module, which is another built in module of node jazz. Let me show you that Const full path is equal to path dot join. First, we pass and disco and Discord their name, which is the whole directory path of our project. Next, we write our folder in which we store the images. Here we go one folder up because currently we are in the routes folder, upload slash products, and then at the third argument, we add our image name. Now here we don't have only single image. We have arrays of image, so we have to run loop for this. Before this, we add product dot Images. So for accessing images, here in the select method, we have to pass images. Good. Now product dot images dot for each. Here, we get each image name, arrow function, and in that, we will move these two lines. Now, here in the fs dot unlink, we pass this full path, and this as dot unlink is an asynchronous operation. So we have to adhere a weight, and for that, we have to make this color function async. Good. Now before running this page, it's better to check we have images array or not. I product dot Images is available and product dot images dot length, greater than zero. Only then we run this loop. Move this code here. In this unlink operation, error might happen. Before this fs dot unlink, we add try and cache blog. Move this unlink method in the tr Blog, and in the cache blog, we get this exception. We simply consult dot error in metics, error, deleting, file, dollar C brackets, full path, comma, add error object. See the changes and take a look. Let's test this implementation, copy the ID of the last product. Also see its image name. These images should be deleted. Replace this product ID with this ID and send this delete request. See, here we get product deleted successfully, and if we check our products folder, see in this folder, we don't get those images. That's how we delete product and its images. Now let's also add that product which we just deleted. So and create a new product API and here I change this title to new product name. Select here images. And simply send this request. Here, I get valid token because this previous one is expired. We go to login API, copy the token, and in the headers, we paste this token. Now, let's send this request. See, here we get new data. Lovely. See you in the next lesson. 130. Searching Product by Title [OPTIONAL]: Now on all ecommerce application, we have the searching feature where at the bottom of the search bar, we can display suggestion. So we have to define API for that. Also, this API will call when each character enter in the search bar. So outer dot cat, endpoint two slash suggestions, async callback function with request and response. In this, first of all, we get what user is searching. So cost search is equal to request dot query dot Sarge here, we have to use regular expression for comparing and finding the string in the title. So Const products is equal to await product dot find passier condition Object, title to object. Here, we use dollar regex, which is the latest way to write regular expression in Mongo Dib. Here we pass our search text and to disable case sensitive, we pass here dollar options to string I. Here, we compare our search string with our title. This will give us products which have that word or string. Also, in the sucesion, we don't want to show all details like description and all. So we can add here Selec method and we only get underscore ID and title property. Also we can limit this data to ten on the front end, we only suggest ten products at the bottom of the search bar. At the end, we simply response dot Json these products. Save the changes, and let's taste this API. Open Postman, create a new request called Get suggestions. URL to API products, slash suggestions, question mark for passing query parameter, search is equal to IP. Make sure we select the Get method and send the request. See, here we don't get products. Let's see what we get in the terminal. See, here we are getting some issues with object ID. But in our suggestion API, we don't have any object ID. So why we are getting here, object ID error. Actually, this API call is not reaching to the suggestions API. It is moving inside this get single product API. Let me explain to you this. Here is the first API URL for the single product. We have API products slash product ID. We add another API API products, slash suggestions. Now Express is getting confused. This suggestion string is object ID or what. Because of that, our single product API is running. What is the solution here? Nothing, we just have to move our suggestions API before this single product API. By that, Express compare our API with suggestion string, and if that doesn't match, only then Express will move to the single product API. Phase changes and make sure server is running properly. In the postman, let's send the same request. See, now we get product suggestions. I intentionally created this error to show you what can happen when you create project by your own. Now in the next section, we will learn how to handle errors like professional. C in the next section. 131. Section 11 - Why we handle errors?: Currently we are running our application in the ideal world. Everything is working perfectly. But in the real world, anything can go wrong. Any error can occur. For example, some file isn't found or our connection with Mongo Deb server doesn't get succeed or user don't pass the valid information or anything can go wrong. In those cases, we have to handle errors, and here are some reasons for handling error. First of all, when we handle errors, we can send friendly error message and we can display that friendly error on the web page like server has some issues, please try again later, like this. Second reason for handling errors, we can log or in simple words, we can store the errors in the separate file, and then look those errors, which errors are happening very often, and by that, we can solve that errors in our application. So handling errors can also improve our application. Now let me show you one error. Let's run our application using nodemon index dot js. Now in the postman, we are also getting suggestions by Sarge. Now suppose Mongoib server get crashed. So to demonstrate, we can comment out the connection code from the index dot js file. Save the changes, and let's go back to the postman. Send the same request again. See here we get loading, loading, and loading. And after 10 seconds, we get error. And if we check our application terminal, see here we get Mongoose error operation products dot Find Buffering Time out after 10,000 milliseconds. And after that, our application might get crashed. Suppose in the real world, our Mongo Deb server gets off for even two to 3 minutes, then our app can crash in production. After some time, Mongo Di B server again comes live. Even if it is live, our app will stay crashed and we can't send data to the client, it's important to handle these types of error. Also, handling errors doesn't mean error not happen. Handling errors means by that error, our server will not get crashed. Currently, this application is running, but before this version of node Jaz previously, node applications are getting crashed. During this section, we will see how to handle errors and log them. 132. Handling Rejected Promises: First of all, let's handle errors which happens when we are dealing with API promises. In this suggestions API, we call here this product collection. And as we know, this is asynchronous operation, that's why we use await for the response. So we have here promise and that promise gets rejected. But here we didn't handle errors in the dry and catch block, which we learn in section six. Remember, so here at try and catch block, here in the cache blog, we get error object. Now, what do we want to do in this cache blog? In the cache blog in real world, we first log the error or exception somewhere in the file or in the database, and after that, we will return response with relevant status code and error message. Currently, we are just logging the error in the console. In future, we will save that error or exception in separate file. Now, after logging the error, we return response with status code 500, which is server error. After that, we also return JSON object with message property called internal server error. Or you can write something went wrong on the server. We can write any error message we want. Good. Now we can move our whole code in this dry blog. Let's see what happens, see the changes, and here our application gets restart. But still, our Mongoib database is not connected. Now let's send the request for suggestions. Let it loading. After 10 seconds, see, here we get the response with 500 status code and with our error message. Also, let's see what we get in the console. See, here we get this mongoose error, same as before, and also our application don't get crashed by this error. Still, our application is running, we successfully handle our rejected promise error. Here we don't consult or log this error, then in our terminal, we don't even know we got error. Now, if we try to access our other APIs, for example, we send this all products request. After 10 seconds, we get here error, and in the terminal, our application don't get crashed. So as we can see how we can handle promise rejection error by using try and catch block. By this way, our application don't get crashed, and that's why handling error is important. For all routes, we have to wrap our whole code with try and cache block. But here in our application, we have almost ten to 15 API routes. We have to wrap all our API route code in try and catch Blog, which is repeating. Also, if one day we want to change the error message or change the logging logic, then we have to update it in all our routes. Now you might ask, is there any shortcut for that? Yes, there is shortcut and we will see that in the next lesson. 133. Create Error Middleware: In the previous lesson, we seen we have to repeat this logging error and returning the error response in every API route. In this lesson, we will create a common middleware in which we will write code for this logging error and returning error response. Don't worry, it is really simple. First of all, in our index dot gs file at the bottom, after all routes, we add app dot g here we pass function, and as we know, here we get three parameters, request response, and next function. Now in this function, we will write all logic for error handling. First of all, we add here console dot log. Error, middleware is running to just make sure this is working. Now back to our route, cut this code inside the cache block and simply paste it in our new middleware function. Now if we want to change the error message or any logic related to error handling, then we have to do changes here at the single place. Now here is one thing. How can we get this error object in this function? We get this error object as first parameter in this callback function. Make sure we get the error object as first parameter. Now let's see how can we call this middleware? So vector out and here in the cache block for calling the next middleware, what we have to do. Right, we can use next function. Here, we get next function as parameter and simply call the next function in the cache block, and we pass error object in this next function. If you are a little confused, then let me show you the code flow of this error middleware. As we know in our back end, we are only running single file, which is this index dot js. So node, start running this code. First, this middleware and static code will run. After that, we have all routes and after that add error middleware. Now when we run next function in any of these routes, that next function will run this error middleware. In all routes, we will call next function, and as the first argument, we pass error object from the cache block. If in our triplog something goes wrong, this case method will run and that cache method called this next function, and that will run this error middleware function. Simple as that. See the changes, and let's check this is working or not. Currently, our application is working, good, open postman, and send the suggestions request. And after 10 seconds, we get error, and in our terminal, we get ramiddalware is running, which means our ramiddleware is working. And after that, we get Mongoose error, great. So if we want to change anything in routes error handling, then we have to do changes at only the single place. 134. Remove try catch blocks: Now our current implementation is good. If you're okay with this, then you can use this approach. But a lot of developers don't like this approach. You can see we have here try and cache block, and we have to repeat this try cache block in every route handler or callback function, which looks a little bit messy. In the ideal world, we should write only this logic. So how can we do this? It is really simple. I just check this Express fi update. In this Express five version, express automatically handle promise rejection error or these errors which happen during the Async operation. Express automatically call this next middleware with error object, which will run our global error middleware. Let me show you that. So now here we don't need this dry and cache blog. We can remove it. So here we are back to our original route syntax. Save this file, and let's check this. Open postman and send the same cugion request. After 10 seconds, we get this error. And if we check our VS code terminal, see, here we first get error middleware is running, and then we get our error, which means our global error middleware is running. This is pretty cool, right? In the older version, like Express four, this automatically error handling is not working. In that, we have to wrap every route logic in dry and cache block, but now we don't need to do that. Express does this automatically, we have to define global error middleware in the index dot js file. Simple as that. 135. Log errors in file: So in this lesson, we will log our error messages in separate log file like this. It is really interesting. Let's do this. So currently, we are only logging the error message in the console. Now it is time to store that error messages in a separate file. So in future, we can see the errors which happening frequently, we can encounter it and improve our application. So for logging the errors in a file, use another NPM package, which is Winst. This is one of the most popular library for logging the errors, and it makes it very simple as well. So open up terminal and write NPM, install WinSternF using the exact same version, we write at direct 3.17 0.0 and hit Enter. Now configure the Winston is really simple. First of all, we import Winston, const, Winston is equal to require and we pass our package name Winston. Now, this Winston by default, give us a logger. This logger is sufficient for small and medium types of application. So we can customize this logger as we want for large and complex types of applications. Now this Winston or logger has transport. This transport is like a delivery vehicle for your logs. It decide where the log should go. A transport takes the logger messages created by Winston and send them to a specific destination. Now the destination could be Console which prints the log to the terminal or command line. Next, we have file for saving the logs into a file on our system, SDTP for sending the log to an API and next, we have database for storing the logs into a database like Mongo DB. At last we have cloud services for sending logs to services like AWS, Datadog, et cetera. These are all transports provided by Winston. Let me show you some of them. This Winston package by default, use Consult transport for printing the logs on terminal, but here we want to also save logs in the separate file, and for that, we have to configure it. So here we write Winston dot Create Logger. Now in this function, have to pass configuration object, or we can say what we want to customize. Now the first configuration is level. This level property define which types of messages we want to store or log. For example, we want to only store errors, or we want to log warnings and errors, both, or we want to log all types of messages. So in Minston we have many levels of logs. First one is error, which is the highest level of log for serious problems. Example, database connection failure. Next, we have war for warnings, info for informational messages like server running on port or one GTB connected, et cetera. Next, we have SDDP verbs debug, Ci. This is the maximum to minimum level of logs. Error is the highest level and CLI is the lowest level of logs. Now, if in the label, we pass info we get log messages of info upper level of that, which is warning and also we get log of errors. If in label, we pass silly, then we get all messages of upper levels. For better practice, we pass here info because we don't want to store silly messages in our log file. Now after the label, we have transports, and here we have to pass all transports which we want to add in array. In simple words, where we want to send our logs. We want to show it in the console or we want to store it in any file. So first of all, for the info warning and errors, we want to show logs in the console. So we add here new Winstn dot transports. Make sure it is transports, not transport and dot Console. For now, let's only console it. I just a minute, we will store these logs in separate file. Now to use this logger, we store it in a variable called logger. And now we can use this logger in our application. But here is one thing. How can this logger know which level of message we are sending? Is it an info or warning or error? Which one? Suppose here at the bottom, we have this simple console dot log server running message. This is an information. So at the place of using console dot log, we can use logger, which we just created, and this logger has all methods according to levels. So if we want to send message as info, then we use here logger dot info. If we have warning, then we use logger dot one. Now we want logger dot info, and let's see we are getting this log in Console or not. See where the changes. And if we check our terminal, see here we get this object level to Info and message server listening on port 3,000. Great. Now, this is not a good format for the log. In the real world, we don't need only label and message. We need much more information about the log like timestamps, et cetera. So in the configuration, we have one more property called format. Here we define how log messages appear. Here we write winston dot format, dot Combine. And in this, we can pass some Winston's format. Like we add Winston dot format, dot T Stem, and after that, winston dot format dot JSON. Don't worry. We have to set up Winston one time only. After that, we just use this logger to print and send logs. Share the changes and take a look. See, now we get timestamp also. Now in our error middleware, here, see, we use console dot log for this error object. So we can use here now, logger dot message. We have to pass the error message, which is error dot message, and we also send the whole error object. Let's see what we get. Save the changes, and let's taste this back to Postman. And we send here get suggestion request. Now after ten second, back to Vas code, open terminal. See, here we get level to error message to the error message, and in the stack property, we get the whole error object, which we pass in the logger dot error method, and at the end, we get time stem. Now let's make this log more advanced. Here we are just getting the log message and log stack, but here we don't get which route caused this error or which method created this error. We want to add that in our log. That will give us specific information. It is really simple. So in the logger dot error, at the place of this second argument, we can pass object. In this object, we can define which are the other properties we want to show. So first, we add stack to error dot stack. Next, we want the API method, so method to request dot method. Next, we want path to request dot original URL. Make sure here you write the right property name. Also, we can order these properties. Suppose we want to show the stag at the end, and first, we want method and then path. So in this object, we can also set the order of properties. But for that, in our format, we have to add this JSN format. Otherwise, it will not work. Save the ins and take a look. Send the request again from the suggestions after 10 seconds back to VS code in the terminal. See, here we get error message method to get path to our API, which caused this error, full stack of this error and timestamp of this error. Lovely. So we are done with the formatting of our log. Now, let's store the log in the separate file, not only in Console. So here in the transport, we add another transport new Winston dot transports dot file. Here we pass the object inside property, file name, logs, smlogs dot log. Make sure we use your file extension dot log, which will help us for understanding what is in the file. Now say the changes and take a look. In the terminal, we get this log info, and if we check our application, our log file is created at logs slamlogs dot log. And if we open this file, see, we get information added in the file. If we send again, get request from the Postman and after 10 seconds, we get here error and if we back to our VSCode, then we get new log level to error. Now some developers like to log only errors in the file, not informations and warnings. I think that is much better. We can also do that. Back to Winston. Here after the file name, we can also specify the level to error. This means only store errors in this file, and also we can change the filename to errors dot log. So if in any of these transports, we don't specify the log level, then that transport will use this global log level. And if we specify the log level in the transports, then it will override this global log level. Suppose for console transport, we add object level to debug. So now for all levels who are about debug, we'll show log in Console and only errors will store in the errors dot log file. So that's how we store logs in separate file, and then we can improve our application according to that. So to summarize, console dot log is not bad. But by using Winston, we can store our logs into a separate file which makes our application more professional. 136. Log errors in mongoDB: Now in this lesson, we will store our logs in our Mongo DB database like this. It is really simple, let's do this. For storing the logs in Mongo DB, we need another Winston package, open up terminal, and here write NPM install Winston Mongo DB, at the rate 6.0 0.0 and hit Enter. Minimize this terminal, great. Now to add this package at the top, we require Winston des Mongo DB. Now in the Winston configuration, we need to add another transport for Mongo DB. So after this file transport, we add new Winston dot transports dot MongoDB. And in this transport, we have to set some options. First one is DB. Here, we have to add database URL. We simply copy this Mongo DB connection URL and paste it here. Also, we can pass the log level by level property to error, and that's it. See the changes, and let's simply check this implementation. Let's run our server if it is not running and send the same suggestions request. After 10 seconds back to Vas code, here we get the error in the console and if we check our database, here we get new log collection, and in that we get our latest error. Here we get timestamp, log level, which is error, error message, and last, we get metadata. This is the same object which we pass at second parameter of logger dot error. See, here we have method, path, and full stack of the error. That's how simple to log errors in the database. If you want to store logs in the database, then you can stay with this transport. And if you want to store logs in separate file, then we can stay with this file transport. Show you the both way, you can use any of them according to your choice. It really depends on you. 137. Uncaught Exceptions: So till now in this project, we have handle errors occur in the route handler and the route handler will pass error or exception to the global error middleware. Now, what if we get error in the rest of node application? We didn't handle it, right? So to demonstrate this, I remove the comment from the Mongo DB connection and simply throw a new error from here. So throw new error, and here we pass error message, something fails in the node application. So the changes, and in our terminal, stop our application, and we run our application using node index dot js. See, here we get error, something fails in the node application, and also our application is crashed. This is called uncaught exception. An uncaught exception is like a surprise guest at a party. You are not prepared for it and it cause chaos because there is no plan for handle it. In simple words, whenever node application runs into a problem or an exception that it doesn't know how to handle, it called an uncoded exception. These are errors in our code, those are not grabbed by a proper try and catch or not handled properly, and as a result, Node just doesn't know what to do and our app get crashed. As our app get crashed, our front end will not get the data from our back end. Our API will not work. So it's important to handle those uncode exceptions. Now the question is, how can we handle uncode exceptions in our node application? Because these exceptions or errors can happen anywhere. How can we handle it? So for that, we have to add listener for our node application. Let me show you. So here after the Winston, we write process dot on. This will help us to add listener for specific event. Now, on which event, we want to listen. Write, it is uncoded exception. Make sure you write the same event name. Otherwise, it will not work. Now what we want to do when uncoded exception happen in our application? That we add callback function and it has error or exception. In the callback function, for now, we simply consult a log this error object. This process dot on is like a watch person. It is keeping eye on our application, and if in our application, any uncod exception occur, process dot on will run this callback function. So at the place of using console dot log, we can use logger dot error. And in that, we have to first pass string uncaught exception, and then we pass whole error stag. Let's check this is working or not. Save the changes, and in the terminal, let's screen the terminal with CLS command, and then we run our application using node index dot js. See, here we get our error in the console and our app is not grassed by itself. But as we can see, we also don't get the info of server running on the port 3,000, which means server is not running. So our application is hanging in the middle. Server is not running, and application is not grassing. So our application is not in the stable state. So what we want to do now have to exit from this unstable state. So after the logger dot error, we simply write process dot exit, and here we pass one as exit code. One means error. Also, we have exit code zero, which means everything is fine, but still we want to exit. And if we pass exit code one, which means some error occur, and that's why we exit. So the changes, and let's run our application one more time. Node, index dot Js and C, now we exit successfully from our application. Beautiful. Now, you might ask this question if after handling the exception, still we are shutting down our application, then what is the point handling the uncaught exception? So handling uncaught exception is not about preventing set down. It is about ensuring the set down happens in an orderly, safe, and informative way. When an uncaught exception occur, our app state is unpredictable. After an unaccepted crash, parts of our app might not work as we want. For example, we got broken database connections, corrupted memory, incomplete request, et cetera. Restarting the app guarantees it starts fresh without leftover issues from the error. Also, in production, tools like PM two, Docker or Kubernets monitor our app. When our app shut down, these tools automatically restart our app. Handling the error ensures the app exit clearly by using process dot exit V, and also it making it easier for the monitoring tool to restart our application without pending issues. Also, one thing I encounter here is when we are doing process dot exit, our logs are not getting stored in the file or in the database, but you can see the log in the console. What is wrong here? So when we do process dot exit, our node application gets terminated immediately. It is not waiting for asynchronous task like logging to a file or a database to complete. In simple words, process dot exit one does not wait for these operations to finish, so the log part can be partially or completely skipped. Now, how can we solve this issue? It is really simple. Have to exit the process after our logger completes its logging process. So after this logger dot error, we write logger dot on, and you guessed it correctly, this is also listener of Winston. Here, we pass our event name, which is finish, and at the second argument, we pass Callback function, and in that, we can simply move this process dot exit one. For better practice, we also logger dot. Save the changes, and let's see it is working or not. Run this application, and if we check our logger file, see, here we get new log, so it is working. 138. Unhandled Promises Rejections: Let's suppose in our node application, we have some promise which gets rejected and we forgot to handle that error using try and cache Blog or cache method. That rejected promise needs to be handled. So to demonstrate that, we remove this through error and we create here a new promise. Let's say cost rejected promise is equal to new promise. As we know, here, we have to pass the callback function with two parameters, dissolve and reject. Now to reject the promise, we simply call here reject method, and here we create a new error and pass error message. What do we write for error? Let's say error in the promise. Sorry about this error message. Now let's consume this promise. Reject a promise dot then and in that error function and we simply consult dot log, promise is working. Can even use here OD, but for that, we have to wrap it with a sin function. That's why I use then method, and here we don't handle the error using cache method. Now let's see what will happen. Save the ings and let's run our application with node index dot js. Here we get log for this error, and as we can see uncaught exception is again called. In the node 15 and above 15 versions, unhandled promise rejection is treated more like an uncout exception. If we didn't handle promise rejection, then it may flow into uncut exception handler. To store separately unhandlePmise rejection, we can duplicate this code and simply change the event to unhandle rejection. Also in the logger, we pass here error message as unhandled promise rejection. See the changes, and let's run this application one more time. See, now we get here error message, unhandled promise rejection. So that's how we can handle uncaught exceptions and unhandlePmise rejection using global listeners. Now, in our application, let's change this console dot log for Mongo Di B connection. What do we write here? Logger dot info. And in the cache method, we replace this console dot log with logger dot error. And also, after the failure of connection, we can exit from our application because our whole application depends on this connection. So we wrap this code with curly brackets. Simply from the global listeners, copy this logger dot on, and logger dot, and paste it here. It will let our application to store the log in the file and database. Now, also, we don't need this error promise and also this then method. So that's how we handle errors and log them for improving and keep tracking of our application. 139. Recap of Error Handling & Logging: Let's quickly recap this section. So before this section in our application, we didn't handle errors. So first, we handle errors for API route handlers. Any error occur in the route handler, that error will send to the next middleware by latest Express, and after all routes in the index dot js file, add error middleware which handles all errors of route handlers. Now, after handling errors, we can store that errors in the files or in the database. So for logging the errors, we use Winston and Winston Des Mongo DB package. Here, we configure the Winston logger in which we specify the global log label format of our log and some transports for send our log to console, file, and even in Mango Di. By these, we can store errors of route handlers. But what if something goes wrong outside of the express? So we define two global listeners, one for uncaught exceptions, and another for unhandled rejection. Remember, if we don't add listener for unhandled rejection, by default, node will treat promise rejection as uncaught exception. Also, in these global listeners, we log the errors and then gracefully set down our application. At the end, this logger dot will stop writing new logs, terminate any pending logs, and close transport streams like file streams, SDDPRquest or database connections for logger. That's all about handling and logging errors. Now in the next section, we will add more features in our ecommerce application. 140. Section 12 - Creating Cart Model: Welcome to another important section of the ultimate No Jz course. In this section, we will move forward in our e commerce project. First, we will add some card features, and then we will integrate payment gateway in our application, which is really important and fun to create. I'm really excited and hope you are too. So let's start this section. Till now in our project, we have added users categories and products API. Now, when user want to purchase any product, he will add their product in the card. So card works like basket or trolley in supermarket. Add all products which we want to purchase, and then we pay for those products. We already know this, right? So we will create a new model for CAT data. So in the models folder, we create a new file called cart dot js. Now for defining the schema, we first Cost Mongoose is equal to require mongoose. And after that, we define st CAT schema is equal to new mongoose dot schema. Here we add our card schema. In this card model, we will store all users card details. So first of all, we need to store user to object type to Mongoose dot schema dot types dot Object ID, ref to user and we simply make it required to true. Now after user, we want which products user added in his card. So we add products filled, and as we know in CAT, user can add multiple products. So it will be the array of products. Now for each product, we store products object, and in that object, we store first product ID. This is again reference, so I simply copy this schema object for user. Paste it here for product ID, and make sure you change this reference user to product. Now, after the product ID, we need quantity of that product. So we add quantity to object, type, to number required to true because that is necessary. Man to, also we can add default to one for safety. Now, if we imagine our front end, we want to show data like this. First, we want to show the product name or title, then price, then quantity, and total. If we only store the product ID in the card data, then we have to run populate to get product details like title, price, image, et cetera, but it will take more time for get the card data. We can use here hybrid approach. If your application needs are different, then you have to stick to the only reference approach. So if you want performance, then you use hybrid, and if you want consistency of the data where your products title, price images are changing more often, then you have to use reference approach. So after the quantity, we add title, type to string, and required to true. After that, we need price, type to number, required to true. After price, we might need image which will be the cover image of the product, type to string and required to true. At last, we need total price, which is the total price of this current product, type to number and required to true. This total price, we will count by price into quantity, right? This is all we need in the products object. Now, what we need more in the cart? Let's see the GRT page again. First of all, in any ecommerce website, we get the number of products in the Nepar or somewhere. And also for the CRT page, we need to display the final price of the product. So we need two more fields in our card schema. First, total products to type number default to zero. If in our card, we have two iPhones and three smart watches, then our total products will be five. And after total products, we need total card price. We can associate as final price, but total card price looks more cool. So total card price, type to number, and also default to zero. Now here you might ask why we need to store the total card price? Why can't we calculate the values when we send card data? The reason why we store the total card price is because, number one, faster display. So when user views their card, the website can show total price instantly without recalculating it every time. This save time, especially if there are many products in the card. Second, reduce work for the server. This is because we don't need to calculate the final price multiple times in lieu. So imagine our user has ten different products in his card. Without total card price, our server has to look through all ten products and add up their prices every time you open card page. Now with total card price, our server just fetches the already store total price. This will save time and efforts, and that's why we store here total card price in the database. Now we have our card schema ready. If in the future, we want to add more fields or we want to remove something, then we can also do that. There is nothing wrong about that. Also, don't stick to an approach. As a developer, we have to always think what makes our application or product more useful and fast for the end users. Simple as that. Now let's create Cart model, seconst card equals to mangos dot model. First, we add singular name, which is cart and at second argument, we pass cart schema. Finally, at the end, we will do module dot exports is equal to CAT. 141. Defining API list for Cart: Now before we start building the APIs for card, let's see which and how many APIs we need to create. This will give us clarity. So here is my process for defining the API list. I started to imagine the front end from the user's perspective. In simple words, I put myself in the shoe of normal user, what the user want to do with card. First one, they want to simply add product in the card. So this is our first API. After adding the product to card, they want to see their own cart, which products they added and how much money they need to purchase. So we need API for getting the current user cart. Also, on the New bar, they like to see the number of products available in the cart. So we can create separate API for only card numbers. After that, on the cart page, they can increase the quantity of products or decrease the quantity of the products, and also they can delete the entire products from the card. Here we need three more APIs, one for increase, second for decrease, and last for the delete product. So here we have the list of APIs for the cart. Of course, we can add or remove APIs from this list. It really depends on us. 142. Adding Products to Cart: Let's start with our first API for CAT, which is adding single product in the card. So in the routes folder, we create a new file called card dot js. Good. Now inside this file, we create Router for API. So Const Express is equal to require Express, and after that, cost Router is equal to express dot Router. And as we know, at the end, we module dot ports is equal to Router. Now before we define the API, let's set this router in our index dot js file. Otherwise, our cart APIs will not work. Save this file, move to index dot js file and simply here const CAT routes is equal to require periods routes CART. Make sure you write here, require not required. Recently, I make this mistake. Now at the bottom, we add app dot g. Here we add prefix API slash CAT. Here we add card routes. Lovely. Now, let's start with head to cart API. So here we add Router. And can you tell me which method we will use? Right, we will use post method. So router dot post endpoint is forward slas here after that, we add route callback with request and response. Now, what we want from the front end? We mainly need two things. First, we need product ID which user wants to add in the card. And second, we want to know the quantity of their product. At a time, user can only add one product with its quantity, and if he wants to add another product, then he has to call this API again. Simple as that. So first, we get details in the request dot body. We can restructure it here and get product ID and quantity. Also for more convenient, we get the product ID in the query parameter. So remove these from here and in the endpoint, we add colon product ID. And to get this product ID, we add here cost product ID is equal to request dot PRAM dot product ID. Good. Now, after that, what we want? Yes, we need user ID also. And how can we get that yes, we can add orthomidalware here, and for getting the user, we can write const user ID is equal to request dot user dot underscore ID. Now, here comes a logical part what we really want to do in the head to cart API. First of all, we will check front and cent product ID and quantity or not. Always start with validation. We add if condition product ID is not available, or quantity is not available, then we return error. So return response, dot status, 400 for missing fields, and dot JSON Object with Menset property, missing required fills. Good. Now, after that, we check, front end pass the valid product ID or not. There any product with that ID in our database? For that, we write cost, product is equal to a weight product dot find By ID, and here we pass product ID. Also, if auto input doesn't work, then we have to manually input this product model. So for using await, we have to make this function async. Now at the bottom, we can put here if condition, if product is not available, we return response which status 404 dot Json. And in the messet property, we pass product not found. Now again, I am asking what we want to do in the Add to Cart API. Let's go step by step. Don't get confused. We want to simply do one thing. We create a new card for the user and simply add current product in the products array with required fills. But there is possibility for that user card is already available. Here, we don't want to create duplicate cards, so we check const card is equal to await card. See auto input works, card dot Fine One. And here in the condition object, we pass user to user ID. Now, as we know at a time, one user have only one card because if you user check out the products after payment successfully, we will delete the user card from the database. If this user has its card, then we get it in the card variable. What if user has no cart? It can first product for card. So we check condition. If cart is not available, then what we want to do? Right, we will create a new card. So new card. And here we pass Object. First, we add user to user ID, product to empty array for now. Total products to zero and total card price to zero. Now, this will return the cart. Here we can simply use this card variable and replace its value because if card is not available, only then we will create new CAT. Otherwise, we get card object in this card variable. We use here card is equal to new cart. So for replacing this card variable, we have to define it by using let. Otherwise, we will get error. Are you clear till this point? And also, if you're a little confused, then don't worry. When we complete this API, we will recap this API from the scratch. By that, your all confusion will go away. So we have cart and we just have to push product in the products array with quantity and other fields which we define in the schema. So we can do cart dot products dot push. And here we pass product object, which we want to push. So object, which are the fields, I really forget. Let me check in the CAT model. Okay. So first, product ID to product ID, quantity to quantity. After that, we have title. Now here, how can we get the product title? Because front end will only pass the product ID. Think about it. So we get product details from this product variable. See here we also check product is valid or not. If product is valid, then we get its detail in the product variable. So now this makes sense why we find product. It will validate the product ID, and also we will get other details as well. So title to product dot title. Price to product dot price, which is the current product price, image, which is the cover image, so product dot Image, which is array, and we simply set the first image. Now you might ask why we don't get these details from the front end. Imagine we get this price detail from the front end. If you surpass zero for any product, the price will be stored as zero for his car. So we clearly can't rely on the front end data. It's better we get real data from the database. Now, after that image, we have total price for that product, which is current price into quantity. So product dot price into quantity. And that's all we need in the products array. Now we have to do just two things. We have to count total products of the card and then total card price. These both are very simple. And do you know which method we will use for counting the sum? Right, we will use reduced method. We write cart dot total products is equal to cart dot products, which is array dot reduce, as we know, we have to pass two arguments in the reduced method. First one is callback function in which we will calculate the products quantity and then default value of the quantity which is zero. Now in the callback, we get two parameters, total and product, which is a single product object. From the callback, we simply return total plus product dot quantity. In short, this reduced method run the loop for each product and give us the sum of product quantity. Great. Now we have to just calculate the total card price and we will again use reduce method for that. Card dot total card price is equal to cart dot products, dot reduce. Here we again pass two arguments. First one is the callbeck function with total and product object arrow function. And after that, we simply at default value of this total, which is zero. What we return from this callback function. We simply return total plus product dot price into product quantity. Or for simplicity, we can return total plus total price, which we calculated here. Also, I think we don't need this total price field. It is not really making impact. What do you think? Yes, so let's remove it from push method, and also we have to remove that from the schema. Move to car schema and remove this total price filled from the products object. Simple as that. Now we have all card fills filled with details, so we can simply save the card. Await card dot C. After saving the card, we simply return response, dot status, 201 and 200 because here we might create a new card or simply add the products. Also, dot Json object with message, product added to card successfully. And after that, we simply return full cart in the response. If you don't need to send, then you can remove this as well. Now let's test this API implementation because testing is really important. See the changes, and let's go back to the postman. Here in our project, we create a new collection called CAT. And in the CAT collection, we create a new request called ED products to CAT. First, we change the method to post APIURL to local host, Column 3,000 API slash CART SLS and here we have to pass product ID, which we want to add in the AT. For now, I just pass one and send the request. See, here we get authorization token is required because in our API, we added orth middleware. Let's generate fresh token, send the login request, and here we get the token. Copy this. Now in the card API, we go to headers and add here authorization in the value, add beer space and paste our token without any double codes. Now send the request. See, here we get internal server error. And if we check our VS code terminal, here we cannot destructure property, quantity of request dot body. This happens because we don't pass quantity in the request dot body. So head over to Mongoi B Compass. In the products collection, simply copy this iPhone 14 ID back to Postman here at the place of this one, we paste the object ID. And in the body, let me remove these two properties. Now we see raw and simply pass your object with one property, which is quantity to two. And let's send this request. See, here we get product added to card successfully. And here we can see card as well. Let me increase this. See, here we get user, total products to two because we pass quantity to two, total card price to 2598, which is also correct. Also we get here products array with all product object. Here we can see we get current quantity, title, price, and image as well. Now let's try something more. Let's change the quantity to one and simply store the same product. See, here we get product died successfully, total products and total cart price, both are also right. But if we check our products array, see, here we get another product object, even that same product is already available in the products array. In our API, we have one issue. As we can see here, we directly put the product in the products array. What if this product is already available in the products array? That case, we have to just increase the quantity of their product. So here, before card products dot push, we have to check the products which we are adding is already available in the products array or not. It is really simple. So for finding the product, we add CRT dot products, dot Find index. Here, we get single product object, arrow function, and here we pass the condition, product, dot product ID, dot two string is equal to product ID dot toString. Now as we know, this fine index method will return the index value of that product which passed this condition. So we store that in variable called existing product index. And if product is not found in the products array, then it returns minus one as index. So we can use that in if condition. So I existing product index is not equal to minus one, which means product is already available in the products array. That case, we will just increase the quantity of that product, and how can we find that product object? Right, by using this existing product index, so cart dot products in square brackets, we add existing product index. By this, we get product object dot quantity. Plus equals to current quantity. That's it. And if product is not found in the products array, only then we push whole product object in the array. So we adhere s and move this push method in the s blog, and that's it. See the changes. And now before final testing, let's remove full card from the database, and let's create a fresh card. Back to Postman, send the request. Nice, we get one product. Now let's change the quantity to two and simply send the request. See, now our quantity only gets increase, and also total products and total card price is right. Now there is one little issue in this implementation. Product might have enough stock or not. We need to check that before adding product to GAT. So here, after we get product, we pass condition like this. I product, dot stock less than quantity, then we simply return response dot status, 400 dot Json object with message property. Stock is not enough. Now here is one more case. Suppose our product stock is four and we want to add the product in the cart with quantity three. This will pass this if condition. Now, what if this product, which is only four in stock, we already added two product quantity previously and now we want to add three more quantity for the same product. In that case, we have to prevent our product quantity to increase. So tell me where we write our condition. Write, in the existing index condition. I cart dot products in square bracket, existing products, index dot quantity plus quantity which we want to add is greater or equals to product dot stock. If it is true, then we return the same response with status code 400 and in Jasen method, object with message property, stock is not enough. And finally, we have completed our head to cart API. So let's quickly recap this API. First of all, we check if product ID is quantity is passed by front end or not, which we can say it like validate inputs. After that, check product is available in our database or not. If it is not available, then we return error in the response, product not found. After that, check product has stock or not. If it has no stock or less stock than our quantity, then we return response with message, stock is not enough. After that, check user has card or not. If he has no cart, only then we will create new cart. After that, we check product which we want to add is already available in the cart or not. If it is available, then we again check the inal stock. If it is also available, then we just increase the quantity. Also, if product is not available, only then we put the product object with product details. And finally, we count the total products and total cart price using reduced method and save the cart simple as that. That's how we create head to cart API. 143. Getting the User Cart: Now it is exercise time. I want you to create a new API for getting the current card details of the log in user. It is really simple. I know you can do this. Now, let's see the solution. So router dot gt and point to forward slash. After that, we add Async callback function with request and response. Now in the callback function, const card is equal to await card dot find one. Here we pass Object with user to request dot user dot underscore ID, and at the end, simply response dot json, this card. Also, for getting the user in the response, we have to add Orth middleware. And that's it. Let's taste this API, open postman in the card, create a new request called Getting the user card. URL to SDP, Column double forward slash, Local host, Column 3,000 slash API slash CAT slash. And now here we need to pass token. So go to headers and here we add authorization. In the value, we pass bearer space. Now go to the login API, send the request, get here the new token, copy this and simply in our API, we paste this token. Now let's send the request. See, here we get card data. Sounds simple. Also, it is possible current user might don't have the card because he never had any product in the card. If that is the case, then we have to return different response. We write if card is not available, then return response dot status 404 were not found dot Json object with message property, user card is empty. At the end, if we found the card, then we send that card as it is. 144. Increase the Product Quantity: Now, as we know, in the card page, we might need to increase and decrease the product quantity by one. So let's define API for this feature. So Router dot, which method we will use. So as we know, in our card data, we just need to update a little part of the data which is quantity, total products, and total card price. So for updating little data, which method we will use, right, we will use patch method 0.2 increase and here we need the product which user wants to increase the quantity in the cart. We will also add here product ID as route parameter, same as before. Also, we need orthomidal ware because only login user can increase the quantity in the card. After that, we add ACN callback function with request and response arrow function. First of all, we get the product ID from the request dot PRMs, product ID. Now, let's come to logical part of the query. Many students ask me, how can I understand the logic of the query or any feature? Let me give you my trick. Whenever you want to apply any logic, then first of all, describe that logic in simple human language. For example, here we want to find logic of increasing the quantity by one for this given product ID. It simply means we need to first find the current user card because that we want to update. After that, we will find that product in the card products array. And then after we find the product, we simply increase the quantity field of the product. We can also increase total products by one and total card price increase by product current price. At last, we simply save that updated card. See how simple this become after writing the logical steps. First, we find the current user card. Const cart is equal to a weight cart dot Fine one. In the comparison object, we add user to request dot user dot underscore ID. Now it's possible we don't find the card, so it's better to return response with error. I cart is not available, then we return response dot status 404 dot JSON, Object with message card not found. Good. Now let's move to next step, which is finding the product in the CAT products array. We already did that in the head to cart API. Remember, yes, here we use fine index method. We write CAT dot products dot fine index. Here we get single product object, arrow function, and here we return the condition, product dot product ID. This is an object ID, so we have to convert it into string is equal to product ID, which we get from the query parameter. This expression will return the index of the product which we want to update. So we store that in variable called index. Now we get the index. Next, we need to increase the quantity of that index product. So cart dot products in square brackets, we pass index dot quantity plus is equal to one. This means increase one in current quantity. After that, we will also increase the cart dot total products, plus is equal to one, and also card dot total card price, plus is equal to cart dot products in square bracket, index dot Price. And at the end, we will await card dot CV. And finally, response dot Json pass Object with message property, product, quantity increased successfully. Also, we send the card just for testing, and that's it. See how simple and clean our API looks. Now let's test this API, see the changes, and open post Van. Here we create a duplicate of this postcard method and rem its name to increase product quantity by one. Now we can addheCRT increase, slash product ID, which you want to update. Also, here we have header authorization, and also we change the method to patch. Now let's simply send the request. See, here I get invalid token because my token gets expired. So go to log in API, generate a new token. Good. Copy this token. Simply in the increase API, pays the token in the header. Now let's send this request. See, here we get success message, and previously we have three iPhones in our card, and now we have four, so it is working. Also, total products and total card price is also working. Let me ask you one question. What if we pass products ID, which is not available in the products array. We didn't handle that. So here, after getting the index, we pass condition I index is equal to minus one, which means we can't find the index in the card products. Then we return response dot status 404 dot Json Object with message product not found in Card. Let's taste this. So at the place of this product ID, we just pass one and send the request. See, here we get product not found in the cart. Great. Now, which thing can go wrong in the API. Let's think about it. When we increase the product quantity, ideally, that product should be in the stock. For example, if iPhone 14 is only six in the stock, and we already have six iPhones in the cart and we try to increase one more iPhone 14 ideally, we can do that. We can't increase iPhone quantity to seven because we have only six iPhones in the stock. We can also put one more condition before updating the card details. If card dot products in square packet, index dot quantity, equal to product, dot stock. Then we return response dot status, 400 dot JCN Object with message, product, run out of stock Gant increase product by one. Now the question is, how can we get this product dot stock? Right, we need to find a product from the products collection. At the top, after this product ID, we can const product is equal to at product dot Fine By ID, and here we pass product ID. Now, this might happen this product ID is not valid, so we can put here also condition. We already did that in the post API. See here. So let's copy this condition and paste it in our increase API. A at the command before the find method, check if the product exists. Now, let's taste this implementation. So go to Postman, send the request. See, now we get internal server error. Now select the endpoint and press Control plus D or Command plus D. Getting the original product ID. Send the request, C, quantity increase by one. Again, send the request. C, we get six iPhone, our stock is eight, so we send the request two more times. See, we have now eight iPhones and let's send the request one more time. See, here we get error, product run out of stock, can't increase product by one. Now our API is working well. 145. Decrease the Product Quantity: Now let's quickly define an API or decrease the product quantity. It will be also the same. Let's copy this increased API and paste it at the bottom. Now, first of all, we add here top comment, decrease the product quantity. Also, here we change the endpoint to decrease product ID. Now let's check this API step by step, so we make sure we don't forget anything. First, we get the product which we also need. After that, we find the cart good. After that, we find the index, good now here is one thing for decreasing the product quantity to one, we don't need to verify the stock. But also, we need to check one more thing. If currently in our card, we have only one product quantity and we try to decrease that product quantity to one. In that case, we have to remove complete product object from products array. Don't worry, we will write logic for this after we complete update. Just remember, I'm adding here comment, check condition for quantity one. After that, we have to decrease the product quantity to minus is equal to one. Also for the total products, minus is equal to one, and here as well, cart total cart price minus is equal to, here we minus the price from the total. Then we save a card and we change this message to product quantity decrease successfully. Now we have to do little change in this API. Let's move to our comment. Here we add I condition, cart dot products, square bracket, index quantity is greater than bun then we decrease the quantity by one. We move this line in the I block and after that, else, we have to remove complete product object which is available on this index. For removing the item from the array in JavaScript, we use Plis method. So card dot products dot Slic Index which is index we want to remove. And then at the second argument, we pass one, which means we want to only remove one item. By this expression, that whole product object will remove from the products array. Now here is one thing. After removing the whole product object from the products array, we can't table to minus this total card price because here we need the product's price. So we have to do something like this. Card total card price minus is equal to product dot price. This product price we will get from the products collection. So in the increased API, we change this card dot total card price plus is equal to product dot price. So the original product price will added in the total. Save the changes, let's is this API. Duplicate this increased product API and change its name to decrease A change the API endpoint to card decrease and send the request. See, now we have only seven iPhones. Let's decrease it two more times. See, now we have five iPhones and total products and price is also working. That's how we decrease the quantity of the product. 146. Removing Single Product from Cart: Now in our card page, we might have the option to remove the complete product from the card. We don't want to decrease the product quantity one by one. So let's define API for removing the product from the card. So we start with router dot page, endpoint to slash remove slash column product ID. Also, we need current user details, so we add Orth middleware and then an callback function with request and response. Now there are very similar steps as our decrease API. Let's see the API, what we need in the remove product. See first, we need to get a product, then cart. Then also, we need to find the index of the product, and also we need this condition. Copy this code till here and paste it in the remove API. Now go back to decrease API, and as we can see for removing the whole product, we just need this line. We copy this and paste it in our API. Good. Now after that, we have to update cart dot total products and cart dot total cart price. Let's go one by one. Cart dot total products minus is equal to, here we need the quantity of that product which we have in the product object. Suppose we have total products seven and we have four iPhones in the products array. Now if we try to remove full phone data from the cart, then for total products, we have to minus seven minus four is equal to three. So we have to find the quantity which is available in the products array. So before this splice method, we can do something like this. Cart total products, minus is equal to cart dot products. Here, we access that product object which we want to remove, square bracket, index, and then we grab the quantity of that product. You guessed it correctly. We can do the same for the CAT dot total CAT price minus is equal to card dot products, square bracket, index dot quantity into cart dot products in square bracket, index dot PCE. The reason we remove the whole product object at the end because if we remove that object before, how can we access the quantity and price of the product? Now, at last, we simply await card dot C and after that, response dot Json object with message property to product removed successfully, and also send the card with it. Now before we taste this API, we can add one more condition in this API. So imagine we have only one product in the cart and we remove that product as well. Now, instead of storing the blank card in the database, it's better to remove that card for that user. User wants to add new item in the cart, then in the head to cart API, we already put code for creating the new cart. We can check whether that product is the only product or not in the cart. Here, after this index condition, we can add one more if condition. Here we check if cart dot products dot length is equal to one, and CAT dot products in square bracket, index, product ID is equal to product ID, which we get from the perms. If this condition is true, then we can remove the full CAT. So await CAT dot Fine By ID and DLT and passe GAT dot underscore ID. Then we return, response, make sure we add here return. Otherwise, bottom code will also run. So make sure you add here return. Response dot Json object with message property, cart removed successfully. Also, you have to convert this card product ID, dot tostring. Otherwise, our condition will not work, and that's it. Let's taste our implementation, see the changes, and open postman. Duplicate this decrease API, change its name to remove product from cart. Good. Now let's send the API endpoint to slash cart remove product ID, and send the request. And because we have only one product in our cart, we get cart removed successfully. So as you can see, defining the API is not so difficult. Just take steps one by one, and if you get confused, then write comments for each step that will clear many of your doubts. 147. Creating Orders Model: Now before adding the payment gateway, let's create a new orders collection for storing the information about all orders and with their status. So in the models folder, we create a new file called orders dot js. Good. Now, first of all, we import const mangos is equal to require from mangos. After that, cost order schema is equal to nu Mongoose dot schema. And here we define our collection schema. We already know this, right? We created schema many times. Now in the orders collection, we need all things which we added in the card collection. So we copy full schema of the cart. In the order schema, we paste our schema. We have user who order products, total products, and also total card price. Now you might ask why we need this all products data? We need this products data for storing the history of the user order. If user want to see which products they ordered previously, we have to show them these products list. So card and order is two separate things. In card collection, we store all products which user wants to purchase. Products in the card can be added, updated, or removed. But once the user checks out and make payment, the card data is converted into an order, and we remove that card data from the card collection. In order collection, we store data permanent for completed transactions. And by that, users can see their previous orders. Now in this collection, we have to add some more fills. First, we make this total card price to total price. Next, we need payment ID, type string and required to true. This is the ID of the payment. We will get this ID from the payment gateway. And by this ID, we can see which payment method user use for the payment, UPI or card or Net banking or something else. Next, payment status to object, type to string required to true. And in this status, we can mention payment paid or filled. Next, what we want is shipping address, type to string, and required to true. As we move this below the total price for convenience. It doesn't matter. Now, after that, we want order status, type to string, and here we can add possible values for this field, which is enum to array. First value can be pending. Next, we can processing next, CB Also it can be delivered or it can be canceled by default, we will make our order status to pending. Here it is not payment status, it is order status. Now next, we can store the date on which user place this order, created at in object type to date and default value to date dot now. As we want date on which this order gets delivered, delivered at in object type to date. For now, these fields are enough. If in future we need more fields, then as we know, we can easily add fills in this collection. Now let's create collection. So cost order is equal to Mongoose dot model. Here, we pass singular name, which is order, and here we pass order schema. After that, at last, we will module dot exports is equal to order collection, and that's it. 148. Workflow of Payments: Previously, we have done adding and updating the card features. Now, when our user wants to buy the things available in the card, we need to integrate payment in our application. So before diving on the code, directly, let's first understand the full workflow of the payment. So imagine this is our user, see added products to card, and from the card page, click on the checkout or pay button. Step number one is, we will call our checkout API on this button press, as we know, we have our card details in our database, so we get total amount of price of her card. Also, we can pass in which currency she wants to pay. Now in the step two, the details, price and currency, we will send to Payment Gateway. Now step number three, Payment Gateway will create a payment form and display it on her browser or phone. Step number four, see enter her payment details like card or UPI or wallet see want to use, see enter that details in the payment form and click on pay. Remember, user payment details goes to payment gateway, not to the back end, and that's why it is secure. Now step, payment gateway, send the payment details to bank, Bank validate the payment data. If it is true, bank will return success, and if it is false or our user has not sufficient balance or anything goes wrong, bank will return fail. So bank will send this success or fail status to Payment Gateway. Now step number six, payment gateway, send the success or fail status to our back end. If it is success, then we will perform some task in the back end which we want to perform like add the card data to orders collection, set the payment status to paid or anything we want to do. Now after completing the all process at step seven, from the back end, we show the user payment is successful or payment gets failed, simple as that. So payment gateway is like a middleman who takes care of secure payments, mode of payments, and directly transfer money to our account. Now there are many payment gateways available like stripe, paper, razor pay, and much much more. But these three are top. Now, how can we decide which payment gateway we want to use? So if we are targeting the global audience, then stripe is good option because it allows international payments, and it also allows UPI. Now, people also allow international payment, and people is also good option. Now, if our business based in India, then sorpay is best for us. Resorpay can also handle international payments, but it is only suitable for businesses based in India foreign transaction. In simple words, in simple words, business is registered in India and also wants to get foreign transaction. For globally, international businesses, gateways like stripe or paper might be more better choice. So in this course, I will show you both reser p for Indian businesses, and if your business is out of India, then I will also show you paper integration. The reason why I can't show you the stripe because for Demos, stripe don't allow some countries account, but it doesn't matter which payment gateway I show you. If you understand the logic of payment gateway, then you can apply any payment gateway by your own. And that's my main focus. So just see these lessons. I will clear the logic behind the payment gateway. 149. Implementing Razorpay Payment Gateway: Let's set up resupe for our Cardwig node application. We will create and taste payments like this. It will be fun. Also, if you are outside of the India, then you can skip this lesson because you can only register in resupe if you are in India or your business registered in India. After this lesson, we will apply paper payment on which any country user can create account. Now let's roughly see how this payment will work. So when user clicks on the PayNw button, front end will call one API. Let's check out. In that API, we will create order for aserPay by giving some information about our payment. Like how much amount we want to collect from the user and in which currency we want to take payment. Now when RSR PE get this information, it generates order, which is the object of information with unique object ID. And then we need to pass this object ID to the front end. That's the work of first API. Now when front end gets the object ID, front end will open the sor P payment window. Pass the object ID and some details. Now you might ask why we need to pass the object ID. By this object ID only reser PA gets the information about the payment. It will also help us in the payment verification and many more benefits. Now user will enter the payment details and click on pay now. If that is successful payment, then reser Pay generate a unique signature payment ID, and then we will call our second API, which will verify our payment. In the second API, we will verify the payment. Reason we need to verify it because that API is calling from the front end. Anyone can easily manipulate that information and make the payment successful. So we will verify the payment in a very secure way, which we will also implement in this lesson. Only after the verification process, if it is success, then we will create a new order in our orders collection, and then remove that user card. Think of sor pay is like a movie ticket counter. For API one, you go to the counter, which is razor pay, tell them which movie you want to watch by telling them amount and currency, and then they give you ticket, which is unique order ID. Now, for API two, after you show the ticket to security, you watch the movie, The counter verifies that the ticket was used correctly and update the records. So for razor pay in the backend, we need to create two APIs. First, for creating razor pay order, and second API is for verify the payment of razor pay. If we successfully verified the payment, after that, at the last step, we will create a new order in the order collection and remove our card. Now let's start with creating first API, which is for creating ser pay order. In the route folder, you will create a new file called orders dot gs. Now for quickly adding the router, we open card Route file, move this router line at the top, and copy these first two lines. In our orders dot JS file, we paste it here. Now at the bottom, we have to do module dot ports is equal to Router. Now let's at this router in the index dot JS file. So at the top, const, order, Rowe is equal to require. Here we go to the routes folder and orders. And at the bottom, after the card routes, we add app.us slash API slash Order and pass here Order Routes. Good. Now we can focus on building APIs. So router dot post, point to slash checkout. Also, we need moth middleware because we want only log in users can check out, and at last acing callback function with request and response. Here in this API, we want to create ser pay order. And for that, we need ser pay instance. So in the terminal, we install reser pay package, NPM install ser pay at the rate, 2.9 0.5, which is the latest version while I'm recording this scores. Good. Now at the top, we input cost ser P is equal to require ser P. Can you tell me why I give this capital letter? Right because it is class. Now in our API, we create Cast reserp Instance is equal to New reserp inside this, we need to pass object with two properties. Key underscore ID. This is the key ID of our reser pay app. In our application, we will store that key in the dot ENV file because we need to keep that private. So process dot nv dot reser py underscore key underscore ID. Don't worry, we will define them in some time. After key ID, we need key underscore secret to process dot nv dot ser pay, underscore, key, underscore secret. Now, let's set these two variables in the dot ENV file. Sor pay, underscore, key, underscore ID is equal to leave it blank. And next ReserpUnerscore, key, underscore secret. We will add them when we create resorpay account. For now, let's complete our checkout API and after that, we will create reser pay account. After creating the instance, we can create order. Cost order is equal to await reserpy instance dot orders dot Create here we have to pass options object for this order. First one is the amount. Let's say we will pass here 500. After that, we need to pass currency property. This will specify in which currency we want to proceed payment. Suppose we want to do payment in the Indian rupee, then we pass here INR, and if we want to do payment in the US dollar, then we pass here USD. But make sure if you use other country currency, then your reserve pay accounts internal payment should be active. For now, we simply pass INR. And last, we need to pass Unique receip. This is as a name tag for the order. It doesn't affect the payment, but help developers or business to recognize which order is which. For example, if we have multiple orders, we can use this receipt ID to find a specific order in RSR Pi dashboard or in our database. So we pass here backticks received underscore dollar Calibackets, date dot now for generating unique receIps that's it. This will generate order for us. Here we simply return response dot Json here we pass object with few properties. First one, success to true, which means we successfully create order. Second, order ID to order dot ID. Next amount to order dot amount and currency to order dot currency. That's it for the first API. This is not the final API, we will improve it later. Now before going to test this API, let's also create second API so you don't get confused when we do testing. I know you have many questions, but don't worry at the end of this lesson, everything will be clear. After this API, we create a new post API and point to slash payment verify also we need Os middleware for this API and at last, ASN function with request and response. Now in this API, we need three things from the request body. Second object is equal to request dot body. First one is ser pay, underscore order, underscore ID. Next, ser pay, underscore payment, underscore ID, and last ser pay underscore signature. With the help of this order ID and payment ID, we have to create one type of signature. If that signature and ser P underscore signature will equal when we consider our payment is verified. Don't get confused. It is really simple. Secst generated signature is equal to here, we have to use one built in nodejs module which is crypto. At the top, we import const crypto is equal to required crypto. At the bottom in our second API crypto dot create HMAC. This is the Nojs method to create has base message authentication code, HMAC. Now at the first parameter, we have to write the algorithm for creating the HMAC, which is a such a 256. At the second parameter, we have to pass resorp secret. So process dot Env dot resorpUnderscore, K, underscore secret. Now, after this create HMAC method, we add another method called update. This takes which data we want to has. Here we pass back ticks, dollar in Cali packets, reser p underscore, order, underscore ID. Here we add Bar symbol, dollar, Cully packets, sor pe, underscore, payment, underscore ID. After that, we add another method dot digest and here we pass X. I get this code from the reser P documentation. You can read the documentation for more details. This code will generate a signature. Now we can compare it with this reser underscore signature. I generated signature is not equals to ser pay underscore signature. If they are not equal, then here, we return response dot status, 400 dot GSN with Object, success to false and message to invalid payment signature. And after that, we simply respons dot Json success to true and message to payment verified successfully. So if from the front end, someone pass fake order ID or payment ID, then by this process, we can verify it. If payment is not verified, then we return response with filled message. And if it is verified, then we return response with success message. So this is not complete code. We will update it after the tasting. Now before tasting this API, we need key ID and key secret of reser pay. Remember, we leave empty variables in the dart NV file. Let's create an account of ser pay and generate this key ID and secret key. These are very similar to the ID and secret key which we generated while implementing the Google and Facebook authentication. Go to the reserp.com website. And as you can see here, we have only India, Malaysia and Singapore option, which means only these country based businesses can set up reser pay. But also, we can accept payment from any country. So glicon sign up, enter your email address. Then create password. Make sure you follow these password patterns, and click on Continue. This will send OTP to email, so I quickly add the OTP here and click on Verify. Now, here is the thing. Select the country, your business is incorporated, which is India. Can continue, and now we have to follow few more steps. Obvious, we are accepting the payment. It is not simple setup as we are calling another website API. We have to provide our details. Also, these payment platforms can change their interface very often. So if in the future, you don't get the same interface like I'm getting, then don't get confused. Just provide the details they are asking and create account on reser pay. After creating an account, we can create key ID and key secret. Here it is asking for, where would you like to accept payment? For now, select online and start on boarding. Now, next, where are your customers paying from? If your customers are from India, then select India. But here, I select outside India and start on boarding. It will take some time Now we write our name. Make sure you write your legal name. Continue. Next, verify your contact details, write your mobile number, and it will send ODP, write that ODP, and click on Continue. Now accept payment on here I select on my website. If you want for app or anything, then you can also select them and continue. Here, we have to add our website link. Also, ser pay verify this website. Is it legal or not? So if you have your website, then add it here. For now, I don't have, so click on add Letter and add Letter. Now select your business type. I select unregistered. Also, if you select unregistered business type, then you can't accept international payments in the live mode. For that, you need registered business. Currently, we don't have any registered business, but if you have then select registered. Also, don't worry for accepting international payment. We don't need to do some extra work. Just we need registered business, and Reserpy will allow you to accept international payment. Now add your personal Pan number, which all of us have edit here and click on Continue. Here, I get error in my name, so I write my legal name, which I have in the Pun card and continue. Now upload your personal PN card, select, upload, select your document, and open it. It will take some time. And continue. Now they are suggesting us to complete the QIC. Select your business category, I select your education. If you have another category, then select according to that. Next, select your subcategory, select what you want. Next, what is your business model? Also, select this according to your needs and continue. After that, we have to add bank details. Here, we need account number and IFSE code of your account branch. Both you get on your passbook. Make sure you write the account number in which you want to accept payment. I fill these details and click on Continue. It will verify these details. And done. Next, we have to select purpose code. Let me try to directly continue. It is giving error. We have to select purpose code. We can search it by the group. But for testing, I simply select this p00 14 and continue. Next, do you have an importer exporter code? No, I don't have accept the terms and click on Continue. Now it is time for business policy. Here they ask for many important questions like cancellation and refund time. I select these to seven days, you can select according to your needs, refund processing time to three to five days, which is good, but nine to 15 for safety. Also, skipping time, eight to 14 days. Now we have to also provide support contact number. I also try to skip this, but it is giving error. So I write my number and also write my email address and click on Create policy pages. Here you can see pages, click on Continue. Here we have policy links. Continue. Submit your application. Here, I try to complete the video KYC process, but here I get error, so I try multiple times, but nothing happens. I decide to skip this. I close all pages and try to open serpy.com. And try to login with the account which I just created, but it is loading and loading. So open incognito window and openerp.com. If you like the login, enter the email, continue, and enter your password. Good. Here we get SRP dashboard. For now, we are in the taste mode. We can change it from here, but don't change it for now. Now to get the APIkey, we go to the account and setting option. And here, in the website and app setting, we go for API keys and generate Taste key, it will send us OTP, write the OTP and simply click on Submit. See, here we get the key ID and key secret. Now, first, we copy key ID back to VS code, and in the ENV file, we paste the key ID for this variable. Again, copy the key secret and paste it in the ANV file secret variable. Save this file, and from the website, you can simply click on Download for backup. Now, let's test our both APIs. It is working or not. So as we know, we need front end for tasting these APIs, because on the front end, we will open RSRPEPayment page. So here I created one simple SDML page called RSRPFront end template dot SGML. You will get this page below this lesson, and it is also available in the Resources project to folder. Download it and simply d it in your current project. Now, let's run this STML file. So right click on this and click on Copy Path. In our browser, pace this path. See, here we get the title and one simple button. If you want to see what happened when we click on this button, then you can watch the STML file, it is really simple. Let me show you also, we have to change some values. So here at the bottom, in the script tag, I added some variable which you can pass for your data. First, we have order endpoint, which is the endpoint of our first API. And second, we have verification endpoint. You have different endpoints, then you can replace them according to your endpoint. Next, we have shipping address. Here you can write your address. After that, user currency, which I set to INR, but you can also pass USD or Euro, et cetera, if your ser pay has international payment on. After that, we have SRP key ID. Here, you have to write your key ID. I copy my key ID from the ENV file and paste it here. Make sure you write your own key ID. Otherwise, this will not work. Next, we have togon. Here, you have to pass your JWT token. Now, currently, in our application, we set only 2 hours expiry time, which is little annoying for tasting. Because we have to create JWT token again and again. So we can remove the expiry from login and simply add expiry at the final stage of the project. Open user routes, and at the bottom, we remove this object with expired property. Now let's generate token which never expired. Open Postman and open login API and simply send the request. Here, we copy this token and in the SDML file, we simply paste it here. Next, I added this on click event for this pay button. In this, first of all, we call this order API using fetch method and with this token. As we know from the order API, we will get the order data. We get that here. If the data has not success, then we show alert with fail message. Now, what if we get reser pay order successfully from the back end? Then we will open resorb payment window. Here, from the front end, we have to pass these options with reserp. See, here we have key amount, currency, name, order ID, and at last, we have handler. This handler is really important, which is function. RSR P run this handler function when user enter correct information and payment turns successfully. So after a successful payment, we call our second API for verify the payment. If that verification is successful, then we show success alert, and if it fails, then we show field error. And at last for opening resorpe, we create new reserp instance and pass whole options here. Then simply by using reserp dot Open, we open ReserpPayment page with that options. At very last, we have this payment dot field which will run when user enter wrong payment details or if they have not sufficient balance, then this function will run simple as that. Now let's simply taste our implementation. I'm very excited about it. Save this file and back to our browser, refresh the page, and simply click on Taste payment button. Thing happens, that's not fair. Let's check what happens. So on inspect using F 12 here in the console, we can see we get error, access to FechtO checkout API from origin null has been blocked by course policy. This is very popular error for full stack developers. It happens because by default, our Express application can't accept API calls from any origin. Have to enable course in our Express app. So back to VS code, open a new terminal and write, NPM install course and hit Enter. Now in the index dot JS file at the top, we import cost course is equal to require course. Then at the bottom, before this express dot JS and middle where we add app dot Ug here we call this course function, and that's it. Save the changes and make sure our server is running. Good. Now refresh the page and let's again click on payment button. See, RSR P payment window is here. Here we get these types of payment methods like cards, net banking, wallet, bill letter, et cetera. I think UPI is not here because my business is not verified. Now at the left side, we get the price summary, which is five Rupee in the back end in the amount, we pass 500 here we are getting pi rupee. Why? So in the amount filled, we have to pass amount in the smallest unit of the currency. And what is the smallest unit in our country PSA, which is 100 PSA is equal to one rupee. And here we pass 500 PSA, which converts to Pi rupee. So if we change this to, let's say, 50,000, save the changes and refresh the page. And if we again click on the payment button, see, here we get 500 rupee. So make sure about the amount of the payment. That's why I created this front end template, so you can understand whole process very clearly. Also, at the top right side, we can see we are in the tasting mode because we created key ID and key secret for tasting mode. Now, let's taste the payment. So for tasting the payment, first, we go to the cards. Here, for tasting purpose, ser pay provides some card details. Also, they provided whole details on the documentation. I will give you this page link at the right side below of this lesson. So here we go to cards. Let's test Indian card, copy this card number, and in our page, paste it here. Now pass here any future date for expiry, like 12 slash 30 and CVV number, let's pass 111, make the payment, secure the card, maybe later. It is processing and which scenario first we want to test, success or failure, let's go for failure. It is loading. And see, payment failed, and also we get Alert payment failed. Now let's try success. Again, at that card number, see it is loading, select success. And here we get this beautiful animation, and then we get payment successful. And also, we get here payment successfully verified, which we get from our second API. So our both API is working well. If you want to try another payment method, then you can also do that. Just check documentation for that testing method. Now let's update our API for real use. So as we know, our payment is working. Now we can improve our APIs and make it realistic. It is really simple. Let me show you. So what do you want to change in the order API? Number one, currently we are passing static amount here, but that is not right. We have to pass the total card price of the user. Second, we are also passing your currency IR but user can decide in which currency they want to pay. So we want to do these two changes only. Let's start with getting amount from the card. So before this reser instance, we write const, cart and await cart C, autoiput not works. So at the top, cost, cart is equal to require we go one folder up models and in that cart. Now in our API cart dot Fine one, and here in the object, we pass user to request dot user dot underscore ID. Now, this will return cart Object, but we have to pass condition if CAT is not available or CAT dot products dot Length is equals to zero, then we return response with status 404 dot JCN message to CRT not found. Now at the place of this amount, we have to pass cart dot total CRT price into hundred because we have to pass amount in the smallest unit of the currency. Let's taste this, save the changes, and refresh the page and click on Taste Payment. If we check the console, see, here we get error. It is the 404 error, which means card is not found. Oh, remember, in the remove cart lesson, we remove the cart by removing the last product from the products array, so we have to add one product in our cart, go to Postman, open at to cart API. Here we have to update Togan, copy it from the login API, and paste it in the authorization header. Good. Now send the request, product added. It is iPhone, nice. Now back to browser and refresh the page, and again, taste the payment. See, here we get our card price. Now, as we know, in database, we store all products price in US dollar value, and that's why we are getting two iPhones in this price. But if you are using razor pay, your business will be in India and most probably your target users will be Indians as well. So in that case, in the database, you have to store price in the Indian currency. Now, let's suppose you want to target global audience and you store price in the US dollar. In that case, you have to convert that dollar price to Indian currency and then pass it in the amount let me show you how we can do that. So for converting the dollar value in the Indian currency, we need current exchange rate. We can't rely on the static exchange rate. So we will call one API for getting the exact exchange rate. So head over to groom and search exchange rate api.com. This is the popular exchange rate API. Now to get exchange rate, we need API key for that. So here we enter our email and simply click on GetVree Key. Here, we have to create password, accept terms, and generate APIKey. What is this? Complete the verification, and then they will send API activation key in your email. Open that link, and here we get the API key. We can see we can send 1,500 exchange request. If you want to get more request, then you have to pay for that. How all exchange rate APIs works. For now, don't worry about that. Simply copy this key and in our ENV file, we add the exchange score rate score API, underscore key is equal to paste your API key here. Save this file and back to exchange rate page. Here, we have to find the API, go to Doc's overview. Here we have APIs, one for getting all exchange rate, and one for getting the pair. We go to pair conversation. Here, we get the API, so copy this, and in our API, let's create separate function for getting the exchange rate. So Const, watch exchange rate is equal to arrow function. Now in this function, we will call that exchange rate API. So const response is equal to wedge, and here in the backticks, we simply pase the IIURL. Now we have to change a couple of things. Here at the place of your APIE, we have to write dollar Cully brackets, process dot nw dot Exchange, underscore rate, underscore API underscore key. Make sure you write the right ENV variable name. Now at last, we have two currency. First one is the base currency, which is the currency in which we add price in our database, and second one is the target currency in which currency we want to convert. So our base currency is USD because in database, we added products price in USD and we want to convert that currency into INR. So our target currency is INR. Also at the place of passing static value of the target currency, we can make it variable. So in the parameter, we get target currency and we pass that dollar calibract target currency. Now, as we know, fetching API is Async runous task. We have to await here for the response. And for using await, we have to make this function async. Luly. Now this response will return data like this. Here we need this conversation rate. After getting the response, we have to convert that data into JSON. Cost data is equal to await response dot JSON. Now from this function, we can simply return data dot conversation underscore rate. Good. Now in our orderyPI we simply count here amount, count exchange, underscore rate is equal to weight, patch, exchange rate, function, and as argument, we pass our target currency, which is INR. Now after getting the exchange rate, we create const amount is equal to card dot total card price into exchange underscore rate, and we have to round this value. So wrap this expression with parenthesis and simply add dot to fixed and pass here two. Now in the amount, we pass amount into 100. Now let's check this implementation. Save this file back to browser, refresh the page and click on Taste payment. See, now we get the value in the Indian currency. Great. Now, let's suppose we want our user can pass target value. So we get the user target value in the request dot body. Secst object is equal to request dot body, and here we get currency. And for default value, we pass here our database currency, which is USD. Now at the place of this hard coded target currency, we pass our currency variable, which our user pass in the request dot body. Also, here is the one thing. If our base currency and target currency is the same, then we don't need to fetch exchange rate, right? So let's do modification in our code. Before this exchange rate, we pass I condition currency is equal to USD, which is our price value in the database. If both are equal, then we have to do amount is equal to card dot total card price. Else we can calculate amount like this. So we just move these two lines here, remove this const, and at the top, we define let amount is equal to zero. So we replace this amount value according to our condition. And also in the order options, we have to pass this currency, save the chinges and let's taste our implementation. Refer us the page, click on taste payment see, here we get INR because from front end, we are sending currency as INR. If you want to change that, then open STMLFle scroll to these variables. Here, in user currency, we pass CAD for Canadian dollar. Save this file, refresh the page, and send the request. See here we get value in the Canadian dollar. Also, if we don't pass your currency field in the EPI call, save this, refresh the page, and send the request again. See, by default, it peaks USD. Great. Also, if your razor pay account has no international payment feature, then you can't make international payment. It is the policy of the ser pay. If you want to check the international payment feature of your account, then go to your accounts and setting option of your ser Bay account. Make sure you are in the live mode. Here, I can't able to move to e mode because this account is not verified. If you can go in live mode, then go to the international payments in the payment blog. That you can see your international payment feature is on or not. Currently, we are in the testing mode and also test will field in our international payment. So we improve our first API. Now let's move to second one. Now let's improve our second API. Don't worry in that we don't have to do much thing. We will just create a new order data in the database and remove the user card if payment is successful. If payment is not verified, then we are running this code block. I payment is successful, then we can write code here before we return success response. Here we create cost, new order is equal to new order. Make sure we input this order model. So at the top, cost order is equal to require we go one fuler up models and in that orders. Good. Now at the bottom, we have to pass new order object here. First of all, in this order, we add user to request dot user dot underscore ID. After that, we need products, and in that, we will store all products which we order, how can we get this information? Right, we can get it from the back end. Before this order, we find cost, cart is equal to eight cart dot Fine Vn. Here in the object, we pass condition user to request dot user dot underscore ID. Simply in the order products, we pass products to CAT dot products. Next, total products to CRT Total Products. Next, we have total price to CRT total CRT Price. Next, we have shipping address, which we have to get from the front end. For now, leave it as it is. Next, we add payment status to paid, payment ID to reserve pay, underscore, payment, underscore ID. And as extra information, we can store reserpeOder ID, to reserpe underscore, order underscore ID. But we have to add this field in our order schema. After this field, we add reserpeOder ID to string. And that's it. We pass all information which we needed. Now we can store this new order, so await new order dot CV. And after saving the new order, we can remove our card from the database. So await card dot deleteB here we have already card. That's why we directly use card dot delete one. If we don't get here card, then we have to use CRT dot Fine one and delete method like this, and that's it. Now we just have to pass shipping address in the order property. So tell me from where we get the shipping address. Right, we get it from the front end. In the payment verify request body, we can get shipping address because from the front end, we already pass the shipping address. See here I pass the shipping address. Now let me give you one situation. Imagine user forgot to pass shipping address. Now, how can we deliver the product to that user? We have to make sure user pass this shipping address. So here we can write if shipping address is not available, then we return response with Status Code 400 for bet request, and in the JSON object, we pass message to please provide your delivery address. Now here is one more thing. We know this payment verify API will run after the payment is done. We can't say now user, they don't provide sipping address, so we can do one more thing. We can simply put this condition at the very beginning of our first API. And here we get zipping address from the request dot body. So our front end needs to pass Zipping address in these both APIs. Also, in our order data, we set zipping address to sipping address, and that's it. Here, our implementation part is over. Let's see we are passing zipping address in both APIs or not. So on ser P template file, we can see here in the second API, we are passing zipping address as zipping address, and also in our first API, we are also passing zipping address to zipping address. And if you want to change your address, then you can do that in this variable. Also, in the first API, we remove the currency field for tasting. So we again addit here currency to user currency, and currently, I set it to INR. Nice. Now let's taste or implementation. Save the changes, and let's open Browser, refresh this page, and then click on Taste payment. Here, we don't get some option because amount limit is high for this payment. Here, we have a lot more payment. See, here we get iron currency and we can taste this payment using net banking, select any bank. And see, we get payment filled because amount exceed maximum amount allowed. Now let's try with cards, copy the card number for tasting and paste it here, add any expiry date, CVV to one, save the card, and finally continue. Maybe later Still, we are getting the same error. So the maximum amount is one leg for Indian currency in single payment. In live mode, there is five lag for upper limit. It is just for testing, they set it to one leg. So to test this, we go to our database, Mongo Di become pass and simply lower the USD total card price to 500 and click on Update. Now, let's repress the page, click on Test payment. See, here we get low price, and here we get wallet options also. You can use that also for tasting. Here, we select card, paste the card number, select expiry date, and CVV and click on pay. Select here success. And see, payment successful. And here we get payment successful order placed. Now, if we refresh our database, C, card is removed from here. And if we refresh our database, we get orders collection. See, here we get our order, which has two products and we pay $500 for that. Also we get address, payment ID, and other more details. Also, this order status is for business, which is pending, our order is in pending mode and payment is set to paid. Don't get confused by that. That's how we can implement reser payment gateway. This is very important and fun to create. What do you say? I know this is long one, but you can see what we have implemented in single go. We implement whole payment with testing. You can take 15 to 20 minutes break, enjoy this moment, and then continue this course. So if you want to apply payment in the real world, then from the reser pay, you have to switch to Live mode and then generate key ID and key secret and use them in our back end and also in the front end, and that's it. You can accept payments from the users. 150. International Payment using Paypal: Let's see how we can implement international payment gateway in our node application. So as we know, for global payment, we have two very popular options. We have stripe and we have paper. In this lesson, we will implement paper like this. We will implement it in our back end, taste it with the front end, and also here we can see the taste payments. So it will be fun. This video is for any country people. Let's start this. Also, currently, stripe is request only option for my country, so I can show you the demonstration of Stripe. If in future, they allow, then I will create lesson on that also. Now let's understand the workflow of the Paper payment gateway. So when user click on Checkout button, we will create one API, let's say, create order. API will create order for the paper payment with some details like how much amount we want to get pay, in which currency we want user to pay USD or Euro. Remember, this order is a paper order, not our order collection. Now, this API will generate order ID by using paper and simply return that order ID to front end. By using that order ID, paper will open payment page where user can enter details about payment. Now, after user enter payment details, we'll call another API for capturing that payment. Basically, by this API, we will allow users payment, add in our paper business account, and then we create order data, and after payment successful, we create order data and confirm the user order. So for implementing paper payment, we have to create two APIs in our nodejs backhand. First for creating order, and second one is for capturing the payment in our account. I know you have many questions, but don't worry. After completing this lesson, you will understand whole workflow better. So let's create these two APIs. Also, if you implement SRP payment gateway from the previous lesson, then you have to repeat little stuff like removing token expiry, et cetera. I have to repeat so we all gets on one page. Sorry for that. I hope you can understand this. Now in the routes folder, you have to create a new file called orders dot js. I have created this file with two APIs because in the previous lesson, I show SRP integration, but those two APIs is separate from this payment integration. You can totally ignore that. Now for quickly adding the route, you can simply copy first two lines of code from the card routes and paste it in the Orders route file. At the end, you have to do module dot Xbards is equal to Router. Also, you have to add this router in the index dot js file, so Const Order routes is equal to require Got routes folder and Orders. At the bottom, after the card routes, you can add app.us slash API slash Order and pass Order Routes. Now you can focus on building APIs. So in our file, router dot post and point to slash People slash Create Order. Here we also need Os middleware because we want only logged in users can access this API. Also make sure you input Osmddleware at the top and after that, is in callback with request and response. Now in this function, we know we want to create Paper order. For that, first, we have to configure P. In the configuration folder, we have to create a new file called paper dot js. First of all, we will define variable for some details. So const paper is equal to object. First of all, client ID, which is our application client ID, then client secret, which is the secret key of our paper application, and at last, we also need base URL. This is the base URL of the paper API. These all details we will store in the NNV file because for security reasons. So here we pass process dot w dot paper, underscore client underscore ID. And at the second property, we write process.nw dot paper, underscore secret. And at last, we write process dot E and paper, underscore, base, underscore URL. Now, let's set these three variables in the ENV file. So PPL underscore client underscore ID equals to leave it blank, and next, paper underscore, secret is equal to, and last. Paper underscore base underscore URL is equal to. We will add them when we register paper business account. Okay? For now, leave it as it is. Now in paper when we want to create paper order or we want to capture the payment in bootstep we need to create a unique token like JWT. So for generating that token, we can create function for that. Const G Xs token is equal to arrow function. Now for generating the token, we will use API of official people. So for calling API we will use Axos. Axios is the package for calling API in JavaScript. It is much easier than using fetch method. Pen terminal, NPM, install Axios. Good. Now to use this Axios package at the top, we import cost Axios is equal to require Xos. Now, in our Gate aces to confunction, we await axios dot here, we have to add the SDDP method, which is post. And in this method, at the first position, add API endpoint in backticks, dollar Cali Brackets, dot BRL V one, O oth, two, slash token. Now at the second place, which is the body, we have to pass double codes. Grant, underscore type is equal to client underscore credentials. And at the third place, we pass Configure Object. First, Oh, to object, use a name P dot client ID. And next we have password to ppt client secret. Now after Oath, we add headers to object in double codes content type, two in double codes, applications XWWWFm URL encoded. And that's it for this API. This API will generate excess token for us, so we store that in variable response. And then we simply return response, dot data dot Xs and as code token. Now for using await, we make this function async and also maybe this code can give us error. So it's better to wrap this code in try and cache block. So a try and catch block and move this code in the Try blog. And in the cache, we console dot log, error in fetching access token. And we write this error dot message. Simply at the end, we do module dot exports is equal to object. And here we add paper to paper, or we can write only paper and get access token to get acessTken. Save this file and back to our orders route. Now for creating a new paper order, we will use another P API. You can get all these APIs in the paper documentation. Don't worry about that. So cost response is equal to await Axios for sending requests, and which request we want to send post. So post at the first argument, we have to pass and point Batis dollar Cali Brackets, paper dot aRLlasV two. Slash checkout slash Orders. Also, for using this paper variable, which we define in the paper config file, we have to import it at the top. Const CibacketsPaper, and we also need gat access token is equal to require we go one folder up, config and paper. Also, we import const Axios is equal to require Axos. Now in our API in Axios at the second parameter, we can pass the body of the request. Here we pass object with some properties. First one is intent. This sets the intent of the order to capture. This tells people that the payment will be immediately captured when the user approves it. Because of this, we will immediately capture the payment in second API. Next property we add is purchase underscore units. To array. This represent the items or services the user is buying and how much it cost. For now, we just pass one object, and in that we pass description to shopping cart order, and another property for amount to object. Inside this, we have to pass in which currency we want to accept payment. So currency code to USD and then value to ten. We want from user tenuous D value. Now, after purchase units, we pass application, underscore contexts. This provides paper with instructions on what to do after the user done with paper payment form. So in this object, we have to pass two properties. First one is written underscore URL. This is the URL on which we want to redirect our user after payment successfully verified by paper. And second property is cancel underscore URL, this is the URL on which we want to redirect user after payment rejected or cancel. For now, leave this field as it is. We will fill this when we taste this implementation. Now, after the body of the request, we can pass other configures like header to object, content type to application, ZSN and we also have to pass authorization header to Batis beer, space, and here we will add people token. Can you tell how can we generate that token? We can use GxssTkenFunction. At the top const token is equal to a weight because this is AN function, get excess token in the authorization header, we will pass dollar Calibrakets token, and that's it for this paper API. Now this API will create a new order like written data, like order ID, and some links. Here we just need to return link, which is the paper link. If we open that link in the browser, then we will get paper payment page. So we simply return respons dot Json Object approval URL, two respons dot theta dot Links dot find. Here we get single link arrow function, link dot L is equal to codes, approve the outside dot HRF, and that's it. Our first API is complete. Now let's quickly define our second API for capturing the payment, and then we will test this implementation. So router, dot post, and point to slash paper capture Order. After that is in call back with request and response. Now, capturing payment is very simple. First of all, we will get order ID from the request dot body because from the front end, we have to send it and we need this order ID to capture payment. Also, for verification, we can put condition here, if Order ID is not available, then we simply return response dot status, 400 dot Json Object with message property, please send Order ID or provide Order ID. Provide sounds good. What do you say? Yes. Now if we have order ID, then we need token for PL capture API. So Gs token is equal to await, G excess token, and at the end, we will simply call one API. Await axios dot post for endpoint, we pass Bc taxes, dollar CLacketsP dot BRL two, slash checkouts Orders dollar Cali brackets, Order ID. As capture. Now at the second parameter, we need to pass body. For this API, we don't need to pass anything, so we pass empty object. Now we get the status and some details about the capture from this API. So we can store that in response, and at the end, we simply return response dot Json object status to response, dot data, dot status. This status will indicate that payment captured successfully or not, and that's it. You can see how simple it is. We just need to call People API. Now you might ask, why can't we call these APIs from the front end? Suppose we directly call this create order API from the front end. Now, as we know, user have excess of the front end. They can simply modify this amount value and make it zero or 0.5. Imagine how much money company will lost, and also some people will misuse some informations. So that's why we have to implement these payment features in our back end. Here we complete our two APIs for p. Don't worry, this is just a basic implementation. We will improve these APIs after testing because in the second API, after capturing the payment successfully, we have to create a new order for that user and remove the card details. For now, we don't want that complexity, so we will do that later in this lesson, right? Before testing these APIs, we need paper client key, People secret, and People base URL. Remember, we use empty variables in the ENV file, we need to add these three fields first, and for that, we have to set up People Business account. Now let's set up Paper Business account. Let's create a new paper account and taste this implementation. In this process, you may need some legal documents and your bank details. So head over to paper Developer page, which is developer.paper.com. If you already have paper Business account, then it is good, but most of students don't have paper business account. Here I am talking about business account, not personal. You can also convert your personal account to business account from this setting. Here we click C sign up for creating new account. Make sure here you select the business account and get started. Enter your email here and submit it. Now here, create your password. Make sure you follow this instruction and submit it. Now, describe your business type, I select your individual, and here we have to also give this information. Product or service, let's say, market places. I'm writing random details, but in the real world, you have to write your original details. Purpose code, let me see what they have. Select your entertainment services. After that, I have to write my identity card number. For your country, it might be something else, so you have to write that correct details. Statement name to, let's say, God bless you and submit the form. Now here, we have to fill the information about personal and business, so I quickly fill these details. So these payment platforms change their interface very often. So if in the future, you don't get the same interface like I'm getting, then don't get confused. Just provide the details they are asking and create business account on paper. After creating an account, we can create client ID and client secret. Also, here I select primary currency to US dollar. You can choose whatever you want to agree and continue. Here they are asking for verify your identity. If you are planning to make your payments in the live mode, then complete this process as soon as possible. For now, I just want to testing, select, do it later. This will move us on the paperboard page. Now at the top, click on developers, and as you can see, now we are in the Sandbox mode, which means testing mode. Now to create client ID and client secret, we go to apps and credentials. Click on Create App. Write your app name, anything. Let's say Cardwish node. We are creating account for merchant and simply create app. It is loading and see, here we get client ID and secret. So first, copy client ID and paste it in our ENV file client ID. Now, copy secret key and also paste it at secret value. For paper based URL, we pass TDPs, colon, double forward slash api.sandbox.people.com. Good. Save this file. Now for testing with payment, we also need sandbox testing account for sending payment. So we go to testing tools and se like sandbox accounts see, here we get two testing accounts, one for business, and one for personal. Right now, we don't need to create a new account. If we need, then we will create. Now, as we know, we need front end for tasting this API because on the front end, we will open paper payment page. Now, as we know, we need front end for tasting these APIs because on the front end, we will open paper payment page. So here I created one simple SDML page call p tasting dot SDML. You will get this page below this lesson, and it is also available in the resources project to folder. Download it and simply add it in your current project. Now, let's run this SDMLFle in Browser. So go to SDMLFle in the file Explorer or Finder and simply open it in the Chrome. Here we get the title and one simple button. If you want to see what happened when we click on this button, then you can watch the SDML file. It is really simple. See, currently it is running from local files of our machine. Now, here is the one thing. Remember, in the order API, we have to pass application contacts. See, here. Basically, we have to pass the Success page and cancel page. In the order API, we can't pass Local folder path, we have to pass URL. So what is the solution here? We can host our SDML file on Local server, and then we will pass that path here. Let me show you it is really simple. So in the extension tab, search Live Server. And install this extension. By using this extension, we can run our application on local server. Back to files and right link on the paper tasting SDMLFle and select open with Live Server. And see it is open in the browser, but now it is running on this port. Simply copy this URL, back to Vas code, and simply paste it in the written URL and also in the Cancel URL, paste the same URL. But for checking, this is working or not, we pass here cancel. In the real world to ask front end developer which page they want to show on success and cancel and change the path according to that. I pass this path just for testing. Save this file and make sure server is running. Here, I get error, duplicate parameters. Oh, here I pass response at the place of request. And also, let me check another API. Yes, here also request. Save this file and make sure our server is running. Good. It is working. Now back to room and simply click on pay with papal. Nothing happens. That's not fair. Let's check what happens. So pan inspect using FL, go to Console, and here we can see we get error. Access to fetch or create order API from origin Null has been blocked by course policy. This is very popular error for full stack developers. It happens because by default, our Express application can't accept API calls from any origin. We have to enable course in our Express app. So back to terminal and write NPM install CRE. And hit Enter. Now in the index js file at the top, we import cost. Course is equal to require course. Then at the bottom, before this express DJs and middleware, we add app dot g course, and that's it. See the changes. Make sure our server is running. Good. Now simply click on pay with paper button. Here I get error in creating order, which means we are getting error in API one. Let's check what is happening here. So open Console. Here I get 400 bad request. So back to VS code in the terminal, C, we get token as bearer. Enter your JWT token, which means we pass wrong token from the front end. So open paper testing dot SDMLFle here we have to enter our token. Open Postman, open login API, generate a new token. Good, copy this token, and in our STML file, pass this token. Save this file, less this. Click on pay with paper. It will take some time and see, here we get login page of paper, which means our first create order API is working well. Now before login, let's cancel the payment. See, we redirect to cancel URL. Now go back two times for our front end paths and click on pay with Paper. We get Paper login page. Here in the real world, our customer will log in with their paper ID and password. But here for tasting, we will use Sandbox account. Think of paper Sandbox account is like Dummi account for tasting. So we go to our Paper Dashboard. Here we have personal account. Click on that. Here, see, we get login info copy email and on our front end, add that email. Now back to Dashboard and copy password and paste it in the password and click on Login. Here we get written to merchant error. We are not able to process your payment using your paper account at this time. Please go back to merchant and try using a different payment method. So let me try again. See, still, we are getting the same error. Now let me try something else. Currently, my application is based in Indian account, and here I am trying to pay for India to India. Paper does not allow domestic payments within India via paper wallets. Even in the sandbox account, we try a transaction between two Indian accounts, then it will also give us error for India to India payment have another payment gateway like raiser pay. Let's create a testing account for another country. Account type to personal and here, select any country but not select the same country as that business account. Create account. Now let's try to log in with this new account. Back to our front end. Here, I'm getting the same error because my account is logged in. So let's open this front end in incognito tab and pay with paper. Here, I get login page. Make sure you log in with another country account, Addhe email, and also add here password and log in with this account. See, here we get the paper payment page. At the top, we get the user account, and here we get price to pay. Also, here at the bottom, we get various payment methods like paper Balance, Credit Union by using card, A paper credit, and you can also add your own card. This is testing account, and that's why we don't do anything. Also, here we get the address of this account. These are details of the tasting account. Now let's click on Continue to review order. S, here we get payment failed. Let me check what is wrong. Open Console using F well and see, here we get error in capture order API. So in our VS code in the terminal, here I get this long error, so quickly scroll to the top. Here we get error, cannot read properties of undefined reading status. So in our second API, we are not getting status. Let me check what is wrong. Oh, sorry. Here, I forgot to write away. Save this file and back to our front end. Let me try to remove this token and pair ID from the URL and run this simple SGML file. Now click on pay with Paper. See we get the papal payment, simply click on Continue to review order. Here I again get payment fill. Remember, whenever we apply any new features, errors will definitely come. Don't get frustrated, focus on the solutions, not on problems. See, here I get internal server error. Let me check the terminal request filled with Status Code 400 in our capture order API, which means we are not getting the order ID. Oh, here I only write request dot body. Have to add dot order ID, save the changes, and in our front end, pay with paper. Continue to review order. See, we move to our success page, and here we also get payment successful, which means our second API capturing payment is also working. See, in our URL, also we get Token, which is the order ID, and we will fetch this parameter in our front end, and then we call second capturing payment API and pass that order ID in the body. And by that we capture the payment in paper account. Let's check our business account, get the payment of $10 or not. For that, we have to go Pap dashboard. In the testing tools, go to sandbox notifications. Now from this drop down, we select our business account and click on search. And at the bottom, we get the payment. If you don't get here payment, make sure you wait for two to 3 minutes because sometimes it takes time to show the payment here. Now if we open this, then we can see received payment $10 from John, which is testing account name. Here we can see transaction date. This is PST format, which is specific standard time. Don't get confused by that. Now you might ask why we get payment in this business account. The reason we get payment in this business account because using this account, we create our application and then we get client ID and paper secret. That's why we get payment in this business account. Now here we taste payment for US user. See, here we get the country code. Now for tasting another country payment, we can create a new account. Select here personal, which is buyer account, and here we can select country. Let's say I select here country, Canada, you can select any country and create account. This is really fun. See, at the top, we get the new account for Canadian user. Open that user and simply copy the email ID. Now back to our front end and here we go to simple paper testing URL. Make sure we remove this token because it is the after page of the successful payment. Now click on pay with paper. Here we again get the previous account because we have logged in with it. So to remove this account, we click here on this JD icon. See at the bottom, we get Logout. Click on that. Now, click on this change user email and paste here this new account email. Now back to deskbard, copy the password and paste it here and log in with it. Good. Now, see here at the top, I get the amount in order, but here from my account, I can pay in Canadian currency, which is CAD. Also, we get limited payment methods, and see here we get people's conversation rate one CAD equals to 0.6 9549 USD. Here, people at their transaction fees, but we can pay in our country currency. Let's continue to review order. See, here we get payments successful. And if we check our sandbox notifications, search here for the business account. It may take little time, and here we get another $10 payment. At the bottom, as we can see, we get the location of Canada. Also, this business account get their payment in the USD, even customer pay in other currency. That customer needs to pay the papal transaction fee. So as we know, our payment is working. Now we can improve our APIs and make it realistic. It is really simple. Let me show you. So what we want to change in the order API, so currently we are passing static amount here, but that is not right. We have to pass the total card price of the user. So let's get this total card price. So before this get access token, we write cost, cart is equal to a weight, cart Make sure you input this card model dot Fine one. And here in the object, we pass user to request dot user dot underscore ID. And also, for this user ID, we need to add Osmidalware here. Make sure you input this as well. This will return card object, but we have to pass her condition if cart is not available or card products dot length is equal to zero, then we return response with status code 404 dot Json Object, message property to cart not found. Now at the place of this amount, we have to pass card dot total card price. And here we don't change the currency because we want to get payment in the USD. If you want to get payment in another currency, then you can pass that currency code in this currency code. But must check that currency is accepted by paper or not. For now, let's taste this. Save the changes and go to Paper tasting dot SDMLFle let me explain you this code really quick. So here we pass JWT token for which we add product. Currently, in our application, we set only 2 hours expiry time, which is a little annoying for tasting because here we have to create JWT token again and again. So we can remove the expiry from login and simply add expiry at the final stage of the project. So on user routes and at the bottom, we remove this object with expired property. Now let's generate a new token which never expire. Open Bostman and open login API and simply send the request. Good. Here we copy this token in the SDML file, we simply paste it here. Also, you can pass here your shipping address. Now, after that, here I added this on click event for this pay button. In that, first of all, we call our order API using fetch method and with this token. And as we know from the order API, we will get the approval URL. So we get that here. If that data has not success, then we show alert with error in creating order. What if we get approval URL successfully from the back end? Then we will redirect user to that page. Now user enter correct information and payment done successfully. Now people pass token in the URL parameters, which is our order ID. So after a successful payment, we get the token in the URL parameters. After that, we call our second API for capturing the payment. And if that payment captures successfully, then from the back end, we pass status in the response. Here we check the status is completed, then we show success alert and if it fails, then we show failed error, simple as that. Now, let's simply taste our implementation. I'm very excited about it. Save this file and now refresh the page, and let's again, click on the payment button. We get error in creating order if we check the console. See, here we get error. It is 400 errors, which means cart is not found. Or, remember, in the remove cart lesson, we remove the card by removing the last products from the products array. We have to add one product in our card, go to Postman open head to cart API. Here, we have to update token, copy it from the login API and simply paste it in the authorization header. Good. Now let's send the request. C, products added. It is iPhone, nice. Now let's refresh the page, and again, taste payment. See, here we get our card price. Lovely. Now here we simply cancel the payment, and we move to paper tasting dot STMLPage. Good. Now let's improve our second EPI. Don't worry in that we don't have to do much things. We will just create a new order data in the database. Remove the user current card if payment is successful. So here we pass condition I payment is captured successfully, so response dot data dot status, which we get from this capture API, if payment is equals to completed, we write code here in the I block. So here we create cost. New order is equal to new order. Make sure we input this order model. Good. Now we have to pass new order object here. So first of all, in this order, we add user to request dot user dot underscore ID. But here for getting user details, we have to adde or middleware Good. Now, after that, we need products, and in that we will store all products which we order. And how can we get that information? Right, we get it from the back end. So before this order, we find const, Card is equal to await cart dot find one. And here in the object, we pass condition user to request dot user dot underscore ID. Simply in the order products, we pass cart dot products. After that, total products to cart dot total products. Next, we have total price, to cart dot total cart price. Next we have shipping address, which we need to get from the front end. For now, leave it as it is. Next, we add payment status to paid, payment ID to response dot data dot ID. And if you want to save some extra information, then you can assess to that it really depends on you. Also, if you want to add new field, then you have to add that field in our order schema. For now, we pass all information which is needed. Now we can save this new order, so await new order dot save and after saving the new order, we can remove our card from the database. So await card dot DiltO Here we have already card. That's why we directly use card dot Delete one. If we don't get here card, then we have to use cart dot Fine one and delete method like this. At the bottom, we move this response in this blog and return this response. This is really important. Now for safer side, we add condition and simply return here response with status code, 400 SN Object, status property to not complete, and message to payment does not captured successfully. Try again later, and that's it. We just have to pass zipping address in this order object. From where we get the zipping address. We get it from the front end. In the capture order API request body, we can get Zipping address, seconds shipping address is equal to request dot body, dot shipping address. Here we are getting zipping address because from the front end, we already pass the zipping address in the request body. See, here I pass the zipping address. Now, in our order, we can set shipping address to zipping address. Good. Now let me give you one situation. Imagine user forgot to pass this shipping address. How can we deliver the product to that user? So we have to make sure user pass the zipping address. So here we can write I condition, shipping address is not available, then we return response with status code 400 for bet request, and in the JSON object, we pass Message property to please provide your delivery address. Now here is one thing. We know this capturing payment API will run after user pay with paper. We can't say now to user, they don't provide shipping address. Here we can do one thing. We can also simply put this condition at the very beginning of our first API before getting cut. Here we have to get zipping address in the request dot body. So Const shipping address is equal to request dot body, dot shipping address. Make sure you write the right spelling of shipping address. Now our front end needs to pass zipping address in these both APIs, and that's it. Here, our implementation part is over. So currently we have two iPhones in our card. We can check that in the Mongoi become pass. See, here we have this card. Now let's test our new implementation. So back to Browser, refresh the page and click on pay with paper. We can login with any personal test account. S, here we get the card price, and here I use Canadian account. That's why I get this Canadian value. Simply, click on continue to review Order. And see here we get payment successful. And if we check our card data, see our card is removed from here, and if we check the orders collection, then we get here new order. I'm getting two orders because in the previous lesson, also, I taste payment gateway with order collection. And also, here we get address, payment ID, and other more details. Here, this order status is for business order, and payment status is set to paid. Don't get confused by that. So that's how we implement paper payment gateway. This is very important and fun to create what you say. I know this is long one, but you can see what we have implemented in single go. We implement whole payment with testing. You can take 15 to 20 minutes break, enjoy this moment, and then continue this course. Also, if you want to apply payment in real world, then from the paper, you have to switch to live mode and then generate key ID and key secret and use them in our backend. And also, you have to change the paper was URL to simple SDDPs, call a double forward slash api.paper.com. We just need to change these three variables, and that's it. You can accept international payment from users using paper. 151. Getting history of orders: Now let's quickly define other APIs for the orders. Let's find all orders history of current user. After this papal API, we add router dot Get and point to forward slash. Also, for finding the user's information, we add Os middleware, and then using callback function with request and response. Now here we directly get const orders is equal to a weight, order dot find, and here we pass comparison Object, user to request dot user dot underscore ID. Also, we need to short this data by date. Dot short method, and here in the object, we pass created at two minus one for descending order. Here from the orders collection, we don't want to show all fills. Dot select, minus user, minus zipping address, minus payment ID, and at the end, we can send response, dot JSN and pass here these orders. Let's test this API. So on Postman here in the CardwzPject, we create a new folder called Orders. In the Orders folder, we add a new request called Order history. Now endpoint to SCTP, Column double for our slash Local host, Column 3,000 API slash Order and send the request. Sorry, we forgot to pass the JWT token. So go to headers. First, we pass authorization to bearer, and here we pass token. So we again login. Here we get token, copy this token and paste it in this API and send the request. See, here we get the data of orders lovely. Now in the next lesson, we will define our last API for this project. 152. Updating status by admin: Let's create API for admin. By this API, he or she can change the order status to processing, C delivered or anything they want. So router dot page because we want to change only one property, not whole document, and point to slash order D status here we also need the ID of order, so we pass Column Order ID. So we add Os middleware for JWT token. And here we also need to check the user rule. Is it admin or not? So we add here Jack rule, middleware, C auto input did not work. And inside this, we have to pass role, which is admin. Now at the top, let's input this middleware. Const, check role is equal to require we go one folder up, middleware, and in that check role. We already use this in the products route. If you forgot, then you can watch the route code. Now simply we pass acing function with request and response. Great. Now first, we get the order from the orders collection. SecctUdated order is equal to await order dot find By ID. Also, instead of this, we can use fine by ID and update. Here at the first argument, we have to pass order ID, which is request dot params dot order ID. And at the second argument, we pass the object of updated values. So Object order status to whatever value at mean pass. And how can we get that value right from the request body? Here before the updated order, we had cost status is equal to request dot body, dot status. And here we pass order status to the status. And after that, at the third argument, we pass object with new to true. Will tell mangos to return new updated data in this order value. We already seen that in the Mongo DB section. Now it might possible we don't found order. I updated order is not availlabel, then we return response, dot status 404 dot Json Object, message property to order not found. At last, we simply pass response dot json, Object, message property to order status updated successfully, and after that, updated order to updated order. Or we can also remove that and done. If you want to change something, then you can make those changes according to your needs. Let's test this API, open up Postman, add a new request in the orders collection called update order status, select request to page, endpoint to slash API, order. Also select page, order status, and here we add the order ID. From the previous API call, I simply copy this order ID and paste it in the endpoint. Now in our API, we pass the header to authorization, and we also copy the value from the previous API and paste it here. Send the request. Here, I get error. Let me check the terminal. I know check role error. So at the top, I have typo, so I change this to check role. The changes and send the request. See, here we get 403 forbidden error, access denied Admin only. We have to change the user rule for this account. Go to MongoiVCompass, open user's collection and find your account by which you logged in. Minus this, I simply change the rule to admin update it. Now we need to generate the JSN web token again. Go to login and send the request, copy this token and replace our token with this new token. Now in body raw, we also need to pass JSON Object with field status to IB and send the request. See, here we get success message and also updated order data. Lovely. 153. Cleaning up code for index file: So currently our application is clean. Just be messed up with the index dot JS file. We can see this is not looking clean. At the top, many, many require functions for input. After that, we have code for creating logger and global error handlers. After that, we have connection to MongoDB then we apply some middlewares and some routes, and at last we listen to our server. There are many things happening in this index dots file. We can make it clean and store each logic in the separate file. It's not compulsory, but many developers do that, but that can confuse you. So there is another way which is instead of separating the code, we can make it clean by adding commands and separate them from each other. Can choose anyway, it totally depends on you. Let me show you my way. At the top, we have some config, so adhere, command global config. After that, we have this Express, Mongoose, Winston, and course. We addre command, third party modules. That we have this app. We don't want to touch it now. At the top, we add all our inputs. Some of these all route imports about this app and adde comment, custom modules, or you can say routes module. There are no rules for the comment. You can write the comment, whatever you want to call. Just keep in mind this comment will be seen by you in the future. So at that time, you don't get confused. Now, after that, we can adde command for this app, initialize express app. Now here we have this logger and also at the bottom, we have this port, so we can move it here and we can call it constant. After that, for this uncaught exception, we add catch, unhandle synchronous errors that were not caught in try catch blocks. For unhandled rejection, we add catch unhandlePmise rejections. By these commments, we can remember why we add the code even after the long time. After that, here we have database connection. Then we have these two middlewares, so middleware, then for static files, we add serve static files. Then for routes, we add API routes. After that, we have error middleware, so we add custom error handler, and at last start the server. Now, if we check our index dot js file, see, now it looks a little bit cleaner. Yes, separation of the code will make this more cleaner, but it can confuse us also. You can also separate the code. I totally depends on you. So here, our ecommerce project is over. Now, from the next section, we will jump on our project three, which is social media application. 154. Section 13 - Introduction of Project 03: Welcome to the new section of the ultimate Node JS course. From this section, we are going to build a brand new project. Can you guess? Yes, we are going to build social media application back end using NodeJS. We will call this project our Linky Pi. This project is one of my favorite project. Let me explain to you what we will cover in this project. In this project, we will create API for followers following, including sending requests to private accounts, sending email from our application. Also, we will create APIs for post with like and comments. Then we will create API for chat, personal chat and group chat. Also, we will apply real time chatting experiences with socket and many more things. If you really understand and build this project, then your portfolio will really improve. This is going to be fun. Are you excited? I'm really excited and hope you are too. So let's start building this amazing project. 155. Setting up Project 03: Now let's set up our new project. So in the projects folder, I create a new folder called our Linky File. Now, let's open this folder in the VS code. Good. In the terminal, we write NPM in Y for initialization and for creating package JsnFle. Also, let's create index dogs file, which is our main file. Now, as we know, we will set up our application in this file. And for that, we need some packages. So in the terminal, we write NPM, install, Express, Mongos for Mongo DB, cours for enabling the course. Also, we add Dt NV, we need that and hit Enter. It will take some time. Good. Now, let's quickly set up our application. First of all, Const Express is equal to require from Express. After that, st app is equal to, here we call Express for listening this app, we add here dot LISN. Here at the first argument, we have to pass the port. After const app, we define another const port is equal to process nw dot port or 3,000 or 5,000, whatever you like. In the production, our application will take port from the ENV port variable. At the second argument, we have to pass the callback function which simply console dot log. In tis, server is running on port, and here we print our port dollar calibracets port. Also, we have to add some app middle wares. At the top course is equal to require course. And here we add app dot g, simply call here course. And after that, for passing data in JSON, we use app.us, express dot JSON. Without this middleware, we can't get data in the request of the body. Now let's see this implementation. See the changes and in the terminal, nodemon index dot js. C, server is running. Great. Now let's also connect this application with database. For that, we need mangos. So at the top, cost mangos is equal to require from mongoose. Now, after this variable, we add Mongoose dot connect. Here, we have to pass the connection string of our database. Previously, we directly pass the string here, but that is little risky. Let's make this safe. In our project, we create a new file called dot ENV. In this file, we create a new variable called DVEs equal do, Mongo DB, column, double for slash, local host, column 27017, which is our local Mongo B connection string. You can get that from the Mongo Divi Compass, and after that, forwards less. And here we enter our project name, our slinky Pi. Now to use this environment variable, we need to configure D E and V. So in the index Gs file, at the very top, we require dot Env dot config. In the mangos dot Connect method, what we will pass? Right, we pass process dot w dot d. We can see how simple this become after just creating one or two node applications. This will improve gradually and you will get more comfortable with node. Now, as we know, this mangos dot connect returns a promise, so we have to handle that promise. Dot then method, call back function, and here we simply consult dot log, Mango Div connected successfully. Also after then method, we add catch method for handling promise rejection, and here we get error, error function, and we console dot log, Mongo Di connection failed and we simply adhere this error. Let's also check this implementation. Save this file, and in the terminal, see, here we get Mongo Di B connected successfully. For now, this is okay. We will add Winston and Lager at the very end of this project as we need them. Now in the next lesson, we will create our user model. 156. Create User Model: Now it's exercise time. So this is the small sample of user document. Based on these, you have to create user schema. You can also watch previous project code. Don't worry about that. So spend some time and complete this exercise. And after that, watch the solution. Now let's see the solution. So in our project, we create a new folder called models, and in that, we create a new file called users dot js. Good. Now, first of all, we import cost, mangos is equal to require from mangos. And after that, we define const, user schema is equal to new mangos dot schema and here we pass the schema in the object. Now, first of all, for our social media app, we need username to object, type, to string required, to true. Also, we don't want white space in the username. So for that, we pass stream to true. Also mean length to three, and max length, let's say 30 or 40, whatever you want to take. After user name, we add email to object, type to string, required to true, unique to true, dream to true because we don't need space in email also. And we always convert our email to lowercase, so lower case to true as well. After that, we need password to object, type to string, and required to true. We also want to store some profile details of the user, and these details user can add from setting like Instagram. It should not compulsory. So we can get simple profile name, which is type to string, and we don't need it's unique and also we don't need it compulsory, so we don't add here any validators. Now bio to object, type to string. And max length to 150. Next, we add accounts, status, type to string, um, to array. Here, we pass values, active, next, disable and bend. We set default value to active. Next, what we can add, is verified to object, type to bullian and default value to false. Also, after that, we add is private, object, type to bullian and default to false. Next, user can add gender type to string, um to array, and here we pass male, female, non binary, or user can say prefer not to say. Next, we also take phone number to object, type to string because user can add country code in this. And here we also trim to true. Now what we can add, I think this is enough for now. If in the future, we need more details, then we can add more fields in future. Here we have our schema. Now let's create users model. So cost user is equal to Mongos dot model. Here, we pass singular name, which is user. And second, we pass the schema, which is user schema. Now, to interact with this user model, we need to export this. So module exports is equal to user and done. Now in the next lesson, we will create API for register a new user. 157. Registering a New User : Let's create our first EPI for this application. Here, we create a new folder called Routes, and inside this folder, we create a new file called users dot js. Good. Now, first of all, we need to create Router. We import Express is equal to require Express, and after that, cost Router is equal to express dot Router. At the end, we simply module dot exports is equal to Router. Now let's add this route in our main index dot js file. After these inputs, we input cost user routes is equal to require. Here we go to Routes folder slash users. Now, after the middlewares, we add app dot U. Here at the first position, we add prefix for that route. So slash API user. And here we simply add user routes. Now let's create signup API. So back to users route file. Here we add Router dot post and point to forward slash, and then async callback function with request and response. Now, first of all, we need to get fills from the request of the body. But the question is, which fills we need for registering a new user. So for social media applications, companies mostly take minimum data for registering a new user. Because if we take ten to 15 fills as first step of the process, then not many people will create account on our social media application. So it's better we only take that data which is required for our schema. Also, user can easily fill those details, and that's why if you notice, almost all social media application only takes name, email ID of the user and password. Only these fills. They take other fills later from the user settings. That's why opening account on social media apps are really simple. Here we will take only three fills from the user. Cost object is equal to request dot body, and here we get user name, email and password. Now, if we don't get these fills, then we return error. So I username is not valid or email is not available, or password is not available, then we return response with status 400 and we pass Json object with error message missing required form fields. After that, we also pass success to falls. This success field will help front end to show errors. Now, also, here we find user is already available in our database or not. Const user is equal to a weight. Here we add user model, C, auto Input works dot Fine one Object. And here we need dollar or operator to array, and here we pass multiple conditions in separate objects. So our first condition is username to username, and second, email to email. If any of this condition is true, then we get that user. So here we pass condition. If user is available, then return response with status code 400 dot Json object message to here we pass condition. User dot user name is equal to our user name. If this is true, question mark, username is already taken, else email is already registered. And after that, we pass success to falls. Now, if user is not already registered, then we simply create a new user. So cost new user is equal to new user. Here we pass user object, user name to user, or we can simply remove this email to email and password to password. Now, as we know, we don't pass here password in normal text, we need to encrypt it. And for that, which package we use, try to remember it. Yes, it is crypt. So NPM install, crypt, and hit Enter. Good, minimize the terminal, and in our routes file at the top, const, crypt is equal to require crypt. Now in our API, we create Cost het pass is equal to await, we create dot s. And here at the first argument, we have to pass our password, and at the second argument, we pass the salt number, which is ten. Now we can simply set password to st password. And after this, we can simply await new user dot c. What do we want to do after creating new user? Right, we generate JWT token for that user, and for that, we need JSN web token package. So NPM install JSON web token, at the rate 9.0 0.2, and hit Enter. Good. Now minimize this terminal, and let's input this JSN web token at the top. Sacst JWT is equal to require JSN btgon. Now, as we done previously, we create function for generating JSN WebTgon because we also need that in our login API SacstGenerate, token is equal to here we get the data as parameter error function. And in this, we simply return JWT dot sign. At first, we pass the data, and after that, we need to pass JWTs secret key. So process dot nw dot JWT underscore key. Now we need to add this key variable in our ENV file. JWT underscore key is equal to here, we can pass any key which is secure. For example, JWT security key. Don't use this for production. I pass it randomly. You have to create your own security key. Also, here I don't add expiry for our token because for social media application, token expiry is not good. Users wants to quickly access our website. Also, imagine you visit Instagram every day and every day, you have to log in. Should you will use that app for a long time, no. So as a developer, we need to always think from the user's perspective. Now, in our API route callback, we simply const token is equal to generate token. Here at the bottom, I remove Typo from my function name. Now in our generate token function, we have to pass user's data we want to add in our token pay load. So Object, underscore ID to new user dot underscore ID, and user name to newser dot user name. And at the end, we simply return response dot status to 01 for new data creation dot GSN, and we directly pass this token. Now, let's taste this API. So open up Postman. Here we create a new collection, create blank collection for our new project called Our Linky Fi. And in this folder, we add a new folder called users, and in this folder, we add a new request, called register, a new user. Good. Now request type to post, and point to SDDP, Column double forward slash local host, Column 3,000 slash API slash user. And send the request. See, here we get error, 500 cannot destructure missing fills. Let's pass all form fills which are needed. Select body, raw, and here we pass our JSON Object. User name to code, underscore, bless. By the way, this is my Instagram handle name. Next email to code at the red gmail.com. And last, we send password 212-34-5678 and send the request. See, here we get token as response. And if we check our database, here we get our linkifed database, and in the user's collection, see, here we get also new user data. Also, we get account status to active is verified and is private, both are false. We set all these values as default in our users schema. Also, here I forgot to add unique to true for this username because here we want this username to unique for all our users. 158. Exercise - User Login API: Now let's do another exercise. In this exercise, you have to create a login API, which will verify user name and password of the user. We already done that in our previous project, but I want you do that by your own. You can see this verify password code, but the rest of the API, you have to create by your own. I know you can do that, so complete this exercise, and then what's the solution. 159. Solution - User Login API: I hope you complete the exercise or you try to solve it. Now let's see the solution. So Router, dot post, and point to slash login. And here we pass async function with request and response. Now, first of all, in this callback function, we get the data from request body. So cost object is equal to request dot body. And here we get to user name and password. Now we can pass condition if username is not available or password is not available, then we return error. So return response, status, 400 Json. Here we pass Object success to false and message to please provide username and password. Now after that, we will find the user with this user name. Cost user is equal to await user dot Fine one. Here in the object, we pass user name to user name, or we can also remove this. Now it might possible we don't find any user with the given user name. If user is not available, then we return response dot status, 400 dot Json Object with success to false and message to invalid credentials. Now if we found the user, then we need to compare the password using BCRP Library. Second, valid password is equal to await, B crypt dot compare. First, we pass input password, which are front ensend in the request body, and at the second argument, we pass user dot password. We simply pass here another condition I valid password is false or not available, then we return response dot status code 401, which stands for invalid or missing authentication token. Also, we send Json object with success to false and message to invalid credentials. Here, if we specify password not matched, then it means we found user and just password is not matching. Also, here I think we have to pass the same status code for user not found. Change this 400 with 401 and message is also invalid credentials. Now, if password is verified, then we can generate fresh token and send it in the response. So const token is equal to generate token. Here we pass data object with underscore ID to user dot underscore ID, and username to user dot user name. At last response dot Json send this token. That's it. Now let's taste this API. In the postman, we create a new request called Login a user. Here we select SDTP method to post endpoint to SDTP, Column double for or slash, local host, Column 3,000, slash API, slash user slash login, and send the request. See, here we get error, cannot destructure property user name. So here we have to pass data in body. Select body, raw, here we pass object with username to code, bless and password to 12345678 and send the request. See, here we get the message, invalid credentials because I pass a wrong user name. I change my username to original code underscore bless, and send the request. See, here we get the token, which means our API is working well. 160. Implement Access Token & Refresh Token [UPDATE]: Now as we have seen in our previous project on the registration and login, we return to tokens, 14 access token, which is sort leaf or SOT expiry, and another is refresh token, which is long leaf or long expiry token. In short, when the access token get expired, front end send request to some endpoint like repress. In the repress we verify the refresh token, and then we return a new access token. This is the logic. Now let's quickly implement this in our third project. So at the bottom, we have generate token function. We can rename this to generate tokens. Now we need to return to tokens from here. So we store this first token in the variable called excess token, and then here we set it expires in property to let's say 1 hour. In production, we can add excess token expiry to three or 4 hours. But for easily testing for this application, I'm not setting expiry time for excess token. Again, I'm telling you for the testing only, so we don't need to generate another excess token our upcoming APIs. Now duplicate this line, change it variable to refresh token, ta, we change it to object, underscore ID to data dot underscore ID. And here we add expiry scene to 30 days because this is social media application at last, we simply re an object with access token and refresh token. Also, we set different secret key for access token and refresh token. It's not necessary, but it's better we do that. Pt NV file at the place of JWT key, we add access token, key and after that, we define another variable, repress token, key is equal to our secret key. Save this and back to our user out file. Here, we change secret key to access token key. And for refresh token, we change it to refresh token key. Now in the log in API, change this function name to generate tokens. At the place of getting token, we get object and we destructure excess token and refresh token from this function. Good. Now here we re an excess token in the response. Also, can you tell me what we have to do before sending the excess token in the response? Right. We have to store refresh token in the user's collection, and then sell refresh token in the SDTP only cookie. So here we await Bcrt dot s. Here, we pass refresh token, coma we pass here salt to ten. This expression return he token. So we store it in variable called Nu he repres token. After that, user dot repress token is equal to New has repress token. Then we have to await user dot C. Now we just have to set refresh token in the cookie to remember how we use response dot Cookie. Here, we pass the cookie name, which is refresh token. Here we add refresh token and at the third parameter, we need to pass configuration object. Here, first property is SDDP only, which we set to true, secure to false, but make sure for production, you make it true. Same site to streak for same domain, but currently, we set it to none, and at last, we can pass message to 30 days into 24 hours into 60 minutes into 60 seconds into 1,000 milliseconds and done. Now we have to simply copy this logic from token generation to sending response and paste it here in this API. And here, we have to change only user dot underscore ID to new user dot underscore ID, new user dot user name, new user, dot refresh token, and also Nwuser dot save. At last in the response, we also add status to 201. 161. Refresh & Logout Route [UPDATE]: Now, let's create route for refresh, so Route dot post slash refresh and here we add ASN callback function with request and response. Now, first of all, we need to get refresh token from the Cookie. So const user refresh token is equal to request dot Cookie, dot refresh token. Here we don't get this cookie because in our Express middleware, we didn't ddt Cookie parser middleware, and for that, we need Cookie parser package, open up terminal, and here we write NPM install Cookies parser and hit Enter. Good. Now open index dot gs file. At the top, we input const Cookie parser is equal to require Cookie parser. At the bottom, we add app dot g, Cookie parser. Make sure you call this function here. Save this file and back to our route. Here, we pass condition. If user refresh token is not available, then we return response dot status 401 dot Json, and here we pass message. No, refresh token provided. After that, we need user ID who send request for access token and how we will get that from the refresh token, we have to decode this refresh token. Cost decoded user is equal to JWT dot Verify here we pass user refresh token and after that, pass the refresh secret key process dot ENV dot refresh token, key. Now, this expression might return error, so we add here, try and gatchblog simply move this line in the dry blog. And in the cache blog, we return response dot status 403, 44 PDN dot JSON, and we pass your message to invalid refresh token. Also, as we know, when we define variable using cost, it will accessible in this dry blog only. So we have to define it before dry blog. And remove cost from here. Now, after that, cost user is equal to a weight, user dot fine BYD. And here we pass decoded user dot underscore ID. And then if user is not available, then we return response dot status 404 dot Json. And here we add message property to user not found. Now, if we found user, then we have to compare tokens, and for that, we simply use BCRP package. So await, BCRP dot compare. We pass user refresh token, which we get from the cookie and compare it with user dot refresh token. This expression return the result for the comparison. Secons is valid. And also here we pass another condition I is valid is false, then we again return response dot status 403 dot Json with message to refresh token is not valid. Now if token are valid, then what we will do? We will create new tokens, store refresh token in the user's collection, set refresh token in the SDDPOly Cookie, and then return the excess token. These steps we already done in the register and login API. Copy the we simply paste it for refresh API and done. Now let's quickly define API for logout also. Then we will taste these two APIs together. Route, dart post, point to slash Logout. Remember for this project in front end, we have to hit API for slash API, slash user, slash refresh or Logout point because we add them in user's route. Here, we add ASN callback with request and response. Now, can you tell me what should we do in lockout? Right, it is really simple. We have to remove refresh token from the cookie, and then we simply remove the token from the user's collection also. Also, while talking with you about user's collection, I remember we didn't add refresh token filled in the user's collection. So let's do that first, and then we will complete this lockout route. So one user's model, and at the bottom, we add filled astken to object, type, to string. We don't adhere required because when our user lock out, then we need to remove the astken. If we add required, then it will not allow us to do that. Simple as that. Now in the logout API, starting task is very similar to refresh API. For example, we also need to get token from the cookie, find user's refresh token, and then make it null. So let's copy code from the refresh API and paste it here. Good. Now let's check this code from the start. This is good. This is also good till we get the user. Here, we don't need to create tokens, so we can remove this. Also, we don't need to as the token, so we can remove this line, and then here we store null in the repress token. Now at the place of response, dart Cookie, we use response, dot clear Cookie. At first, we pass the cookie name which is okay. After that, here we don't need to pass this refresh token variable, but we need this configuration object, and at last, we simply return message at the place of access token, locked out successfully and done. Now let's quickly test these APIs. So one Postman in the user's folder, we create a new request called repress access token. We need post request. Point to SDD P, Column double forward slash, local host. Column 3,000, slash APIs user, slash repress and send the request. See, here we get error because we don't have Cookie, go to Login Route, send the request with write details. See here we get token and also repress token is set to Cookie. Now back to repress API, send the request again. See, here we get the new token. Great. Now let's taste Logout API. Simply duplicate this request taste and we change the request name to let's say log out a user, and also change the API endpoint to slash user, slash Logout, and send the request. See, we get success message, and if we check the cookie, see, here we don't get a refresh token, both APIs are working well. Also, I want to tell you this current and previous lesson are updated lessons. If in the future, you don't see this code in my screen recording, then don't worry, you can absolutely follow those lessons. I just want to make the coures as up to date as possible. You will also learn current best practice for Node jazz. 162. Current Logged in User Details: Let's create another API for sending the logged in users details. So here we add another router dot Get point to forward slash and simply pass here ASN callback function with request and response. Good. Now in this function, cost user is equal to await user dot find By ID. And here we simply pass user ID. But how can we get that ID? Yes, we need to extract that ID from the JWT token. And for that, we need to create Osmddalware. For now, we complete this API, and then we will add Othmidalware. Here we pass request dot user dot underscore ID. Now, we don't want to send password with this data. We add here dot select method, and in the string, we add minus password. After that, if we don't get the user, then we pass I condition, user is not available, then we return response dot status 404. Also pass dot GSN Object with success to falls and message to user, not found. If we found the user, then we simply return it in response dot Json user. Now many students might ask, can we see the previous projects code while applying it in our new project? Yes, of course, you can see that code. Just think, is there something which you can improve in that code? If yes, then improve it, and if no, then stay with that code. There is nothing wrong about that. Let's create Os middleware. So in our project, we create a new folder called middleware. And in that folder, we create a new middleware file called oth dot js. Now, first of all, here we create a function called OT and we know this is middleware function. So we will get here three parameters, request, response, and next. Now in this function, we first get a token from the request header. Do you remember in which header, our front end will pass the token? Write in the authorization header, SecondstO header is equal to request dot headers dot authorization. After that, we check the condition. If auth header is not available, or oth header dot starts with here in codes, we pass Barr space. If this is not true, then we return error. So return response, dot status 401 for unauthorized Json object, success to force, and message to authorization, token required. Now if we get oth header, then we need to extract our token from that header. So cost token is equal to oth header dot split method, in codes, we pass pace, and here we need second item, so square bracket, index one. We already seen this in the previous project. Right. So now we have a token. The only thing is we need to verify the token and set our users data in request dot user. Secct decoded user is equal to JWT dot Verify. Here, first, we pass our token, which we get from the header. And then in second argument, we pass process dot EV dot JWT underscore key. We can simply set this variable as request dot user. Request dot user is equal to decoded user, and then we call next function. This is most important thing. Now, what if we don't get this decoded user? If we don't handle this, then we will get error. So we handle this with try and catch block. Here we try cache block and simply move these three lines in the try block. In the cache block, we simply return response, dot status, 401, dot Json, Object, success to false and message to invalid token. And done. Now let's export this function. So module dot exports is equal to OT. Now back to our users route. Here in our GIPI, we add oth middleware, see at input works. Nice. Now let's taste this. So when Postman, here we add new request called current locked in user point to SJDP, Column double four slash Local host, Column 3,000 API slash user and send the request. See, here we get error, authorization token is required. So from the previous API call, we copy this JWT token, and in our current API, we go to headers. Here, we add authorization header. Value to Barr space and paste our token and send the request. See, here I get invalid token, but why I pass the valid token. Let's check the terminal. See, server is also running. I think error is happening in the dry and cache block. That's why my server is still running. So here in the cache block, we add console dot log this error. Set the changes and send the request again. Now back to VS code, back to terminal, and here we get error, JWT is not defined. Oh, I forgot to import JWT from the JSON Web token package. So at the top const, JWT is equal to required JSN web token. You can see that's how we can solve error. Don't get panic if errors occur in your code. Try to solve it step by step. If many errors occur, we can learn more about our mistakes, and by that, we can improve our code. So don't worry about errors. See the changes and take a look. See, here we get the usage details without password. 163. Resetting User Password: Now let's implement reset password feature in our application. First, let's understand the overview of this feature. So when user enter their email and clicks on the reset password button, then we will call our first API request Password Reset. Now, this API will generate new token and send a URL with that token on their email. When users clicks on that website link, we will take new password from the user, and when users clicks on submit, we will call our second API reset password. In this API, we will verify that token and update the new password in the user document. If this all works fine, then we will return message, password, successfully reset. Here, we have to create two APIs, request password reset, and reset password. So let's start with creating first API, so Router dot post endpoint to request Ds password, D reset, and also we add ASN callback function with request and response. So here we are not adding orthomidal ware because we want anyone can reset their password. They are doing reset password because in the 99% cases, they forgot their password, so they can't log in, and that's why we don't add here orthomidalware. Now, first of all, we get a user email from the request body. Secons object is equal to request dot body. And here we get the email. Now using this email, let's first check user is available or not. So const user is equal to await user dot Fine one. And here we pass comparison object with email to email. Next, we pass condition. If user is not available, then we return response which status code 404 dot Json Object with success to falls and message two, this email is not registered, or we can also pass user not found. It's totally up to you. Now if user is available, then what we will do? Right, we will generate token. So cost, reset token is equal to JWT dot sine. First, we pass our data, so object, underscore ID to user dot underscore ID. And at the second parameter, we pass JWT key, so process dot Env dot JWT underscore key. And also at the third argument, we pass object with expiries in property to 1 hour because here we want to add these expiries in property, and that's why we don't use here generate to confunction. We have reset token. Now we just want to send it to our user's email. Sending an email is a separate logic, so currently, we don't implement it. First, we create our two reset APIs so it will not confuse you. So here we are writing comment for sending email and then simply return response Json. Here we pass Object with message property, password reset, link, send to email. And after that, we also pass reset token to reset token. Sending this reset token in response because we don't send email yet. It is just for testing. After sending email, we don't need to pass Reset token in the response. Now, let's define our second API in which we will verify that Reset token and save the new password. So router dot post and point to slash reset password. And here we add ASN callback function with request and response. First of all, we get fills from the request body. So Const object is equal to request dot body, and here we destructure reset token and also we get the new password which user wants to update. Here we need to perform two steps. Step one, verify the token, and step two, if token is verified, then update the password. Simple as that. So to verify the token, we can use JWT dot Verify. At first, we pass our reset token. The second argument, we need to add our JWT key process dot ENV dot JWT underscore key. Now, this expression will give us users data which we pass when we generate this token. See here at the top, we pass underscore ID to user dot underscore ID. We store that in variable called decoded user. Now we find user using that underscore ID and then update the password. Let user is equal to await user dot find by ID. And here we pass decoded user dot underscore ID. Now after that, we pass condition. If user is not available, then we return response with Status Code 400 dot Json Object with success to false and message to invalid or expired token. Now if we get the user, then we will simply update the password. Here, for password, we need to first has that password. We can't store it as it is. Await, crypt dot has here, first, we pass new password, and at the second argument, we pass the Salt, which is ten. This will generate a password, so we can directly store that in user dot password, and below that, we simply await user dot CV. And at last, we simply return response dot Json object with message property, password reset successfully, and that's it. In the first API, we generate the reset token and send it with email, and in the second API, user will send that reset token back to us and we will verify it. If it is verified, only then we will update that password. Here in the token verification, we have little security issue. Here we are just verifying the token using JWTkey, but this is not much secure. Let me explain you with simple example. Suppose users send requests for reset password. In the back end, we generate a reset token and send it to the user. Now it might happen, user can again send the request for the reset password, and we again send the new reset token to the user. Now these are two tokens which is validate for resetting the password. Suppose user pass the second token and change the password. Now, what if this first old token hackers get and they change the password using this old reset token. This implementation is little risky. Now, what is the solution here? It is really simple. When we generate a reset token in our first API at the time before sending the email, we will store the reset token in our user's collection. Also we store token expires and time. Now when we verify the token, we will compare the stored reset token with user's reset token. If both are matched and token is not expired, then we will update the password. By this approach only, the latest reset token is valid and only for the expires and time. This approach is more secure than the previous one. So let's implement this. Here before we send email, we write user dot Reset token is equal to reset token, and user dot reset token, expires is equal to date dot now, plus, we want to add 1 hour expires. So 60 minutes into 60 seconds into 1,000. Converting seconds into milliseconds. And after that, we can await user dot c. Also at the top, we convert this const user to at user. And also, we need to add these two fills in our user's model. So when user Schema, here, at the end, we add reset token to object, type to string, and after that, reset token expires to object and type to date, save the changes, and back to our reset API. The verification part, we add condition if user is not available, or user dot reset token is equals to reset token or user dot reset token expires is less or equals to date dot now. If any of these conditions are true, then we will return token expired, and token is not verified. Also, after updating the password, we need to make these two fills null. Before user dot c, we set user dot reset, token is equal to null and user dot reset token expires is equal to null. This is more secure. If user successfully reset the password, there are no tokens which are valid for reset password. Now let's test this implementation. In the Postman, we create a new request called request, reset password, method, to post point to SDDP, Column double forward slash local host, Column 3,000, slash API, slash user, slash request, reset password. And in body, go to raw and here we pass JN object with email. Make sure you pass valid Email and also that email should be in your user email. Otherwise, we will get user not found. If you don't pass valid email in the user's data, then from the Mongo Di become pass, you can change that. Now send the request here, I get Ken not found. Let me check the endpoint. Oh, here it is request, there's password, let's reset. And in my endpoint, I write request, let's reset, des password. So I change this endpoint and send this request. See, here we get a reset token, copy this token, and we need to create a new request called reset password method to post and endpoint to SDDP, Column double forward slash local host, Column 3,000, slash API user, slash reset password. Also, here we need to pass body, raw object with reset token, and paste that token. And then we pass the new password. 123-45-6789. Now send the request. See, we get password reset successfully. So both API are working. Now, the only thing we want to do is we need to send this token or reset page link in user's email, and we will see that in the next lesson. 164. Ways of sending email in Node JS: Now there are many ways to send email from node application. First one is by using SMTP, which is simple mail transfer protocol. Second way is by using SendGrid API, and third way is by Amazon SS, which is simple email service. Now let's see pros and cons for each way, which will help us to decide which email service we can use for our application. So SMTP works best for small applications because it is simple to set up, we need to pass only email and password of our account, and then SMTP will send that email from our account. But SMTP is little slow in compared to other email services. Also, with SMTP, we can only send limited amount of emails. For example, if we use Gmail, then we can only send 500 emails per day. If we use Yahoo, then we can send only 100 emails per day. SMTP is not scalable for big businesses. It is okay for small applications. Now let's move to SNGrid. In SendGrid, we don't need to pass email and password of our account. Instead of that, we need to generate APIKey and we will send email using SendGrids API. So this is fast and reliable. It is also easy to set up. Many companies use SendGrid for sending bulk emails like Uber, AirBnB, app, et cetera. But for sending unlimited emails, we need to purchase its paid plan. Now let's move to Amazon SES. This is the most trusted and secure email service used by big companies like Netflix, LinkedIn, et cetera. It is also very fast. We can send millions of emails per day, and also their paid plan is cheaper than Sandgrad plans, but the only cons is it is little hard to set up. We can manage that. So here, we can clearly see that if we need speed, security, and low cost, then we can use Amazon SES. So in the next lesson, we will implement Amazon SES in our application. 165. Setup Amazon SES for Sending Email: Let's implement Amazon Simple email survey in our node application. It is really simple. I break this down in three steps. Step one, configure the SS in the node application. Step two, creating an Amazon SS account and verify email for testing. Step three, we will send testing email from our API. Here I want to clear one thing for setting up the Amazon SS account, we need payment card details and identity details. We don't need to pay anything, we need card details. Here we will use pre version of Amazon SES. So if you don't have that details, then you can skip this lesson and you can apply free email sender using SMTP in the next lesson. To implement Amazon SES, we need to install AWS package. So NPM install at dit AWS sdk client Ss at the rate 3.738 0.0 and hit Enter. Good. Minimize the terminal. Now in our project, we create a new folder called Config and in that folder, we create a new file called Amazons dot js. First of all, we need to configure SS client and for that, we need SS client method. So Const CL brackets. Here we get SS client is equal to require at the rate aws SDK client Ss. After that, const, as client is equal to new as client and inside it, we have to pass the initialization object. Now the first property of the object is region. Here, we have to pass our region. We will store the region in the ENV file, so we add here process dot ENV Aws Score region. After that, we need to pass credentials property. Now, this is really important. Without this, we can't send email. Here we pass object with excess key ID, and also we need to pass secret excess key. These both properties we will get when we create account on the Amazon AWS. Don't worry. First we set up all these in our node application, and then we will create new account on Amazon Aws. So here we also pass process dot An dot Aws, underscore Xs, underscore key. For secret, we pass process dot n dot Aws, underscore, secret underscore key, and done. Now we just need to create Send Email function and add some email fills. So Const send email is equal to arrow function. Here, before we forgot to add try and cache block, we add them, and in the cache, we simply console dot log, Amazon, SCS error. Here we add this error. Now, let's write our code in try blog. If anything goes wrong, then our cache block will console that error. Now for sending the email, we need to provide some information from email, we want to send email to which email we want to send, what is the subject, what is the body, et cetera. So cost params is equal to object. Here, first we a source, here, we have to pass our verified email address, which we will verified on the Amazon SS website. Don't worry, don't write anything for now. Leave it plan. Make sure you write this properties name in the capital, same as I write. Otherwise, you will get error. Now, after source, we add destination, addhee object with property to address, and here we have to pass array of emails to whom we want to send email. We can also send emails to multiple users. Now, how can we get that email address in this function? Right, from the parameters. So here we add two, which is the email address. Also, we need subject of the email and also we need the text of the email. Now, here in the two address, we add two parameter. Here, if we have multiple, then we can add those email IDs as well with comma. Now after the destination, we add message property to object. First, we add subject to object with data property here, we have to pass the subject which we get from the parameter. Now after subject, we add body to object, text to object, and inside this data to text, which we again get from the parameter. I know this is a little weird syntax, but it is what it is. We need to follow that. Now we have our perms ready. Now we can create command for these perams. Const, command is equal to New send email, command. S, auto input works, and here we simply pass perams. Now we need to send this command for sending the email. So Ss client dot SN, and here we pass command. Now as we know, sending the email will take some time, so it will be an asynchronous task. And for that, we adhere await. And because of await, we need to make this function async. Now let's do the response in the response variable, and at the end, we simply add console dot log, email sent successfully message ID column, and here we return response dot message ID. At the end of this file, we simply module dot exports is equal to send email. Make sure you don't call this function here. We just need to pass the reference. Also, here in the sources, we pass process dot En dot Aws underscore, email, which will be our email from which we want to send email. So here, our step number one is done. We just need to add these three variables in the ENV file and we need to also pass this source email. Head over to browser and go to aws.amazon.com. And here we need to create a new AWS account. Here, we write our email address, and here we need to pass our AWS account name. For now, pass anything, we can change it later from the settings. Click on Verify email address. After that, it will ask for password, simply create a password and continue here we see like personal plan, and also we have to pass our details. I quickly write my details and agree and continue. Now here, we have to pass the card details. If you don't have the card details or you don't want to give your information, then you can implement SMTP because most of students don't have card, so you can implement SMTP, which only uses your email. I will show you that in the next lesson. For now, I pass your card details and then verify and continue. This will process small payment like $1 or even smaller for your card verification. So here I enter my OTP payment is processing and here it is done payment. Now we have to provide identity. Select your personal use. If you want to use for business, then you can select that also. Next, we select individual, and here we need to provide identity document. So I quickly fill this form and also upload my document and click on Continue. Here provides some more details for verification. I write here my phone number and send SMS. If you're from different country, then you might get another fill. Here, I verify my number with OTP and then continue. Now here we just set this basic free plan, and finally complete signup Dn go to the AWS Management Console. See, here we are at the Console. First of all, we will verify our sender email. So at the top, inserg SEs and open this Amazon SS page. Click on these three lines and go to identities to verify email or domain. Here, we have to create identities. Now if you want to use for production, then you have to verify your domain here. But now for testing, we can use your email. Here, we write our email address from which we want to send email to users and click on Create identity. See here we get verification pending. Amazon has S send email to that email and we need to verify that. So here I open that email. Click on this link, see verification done, and if we refresh that page, see here we also get verified. So we have to copy this email and in our node application in the sources, we added AWS underscore email. Let's add this variable in the ENV file. AWS underscore email is equal to here I pass my verified email. Now we have to create access key and secret key for our application. Search here IAM, which is identity and access management. Here we go to users and create a new user. We write user name, let's say, our Linky Pi and click on next. Here we have to attach policies, search here, AS full Xs and select the Amazon SS full cess policy, and click on next and create user. Now for generating the Access key, open this user and go to security credentials. Here we have zero access keys, so we create key, select other option, click on next. Here it is asking for description, but it is optional, simply create access key. See, here we get access key, and also we get secret Access Key. We have to add them in our ENV file. Make sure you download this dot CNV file. In our ENV file, first, I add here variable name, AWS, underscore Xs, underscore key is equal to copy the aces key from the browser and paste it in our ENV file. Also, we add another variable called AWS, underscore secret, underscore key is equal to copy the secret key from the browser, and also paste here. Now we need region. In ENV file, we add AWS underscore region. Now forgetting the region here at the left side of our profile, we get a list of region. I'm from India. That's why I select Mumbai. My region will be AP south one. Here, you have to select yours. If you don't get idea, then you can simply search your region on the Google and select Neal location. I add this region value in the NV file. Now here, our step two is done. So this file unless the sending email function is working or not, which is our step three. In our request, des resets password API, we will call Send Email function at the first argument to pass the email of user. User dot email comma here, we write our email subject. Let's define new variable for subject is equal to password reset, request for your Linkifi account. Also, we define text which we want to send in the back ticks, click this link. Reset your password, SDDP cool and double forward slash, our linkify.com slash reset password. In the query parameter, question mark, reset tocan is equal to here we add dollar curly packets, reset tocan. This URL is for directly access or a front end. So Instagram sense, right. Also, you can modify this text according to your needs, or also you can pass the STML code as the body of the email. Just in the email params at the place of this text, we have to pass STML. Now in the Send Email function, we pass subject and also text. Save the changes unless this send email function is working or not. So one Postman, and here is a request reset password API, which is our first API for reset. Now before calling this, let me pass here valid email so I get reset token on that email. Here, I change my email to one of my dummy email, update it, and also in the request dot body, I pass the same email. Good. Now, let's send the request. See here we get could not send request. Oh sorry, I forgot to start the server. So nodemon index dots Nice. Now, let's send the request. Here I get sendemail is not defined. I forgot to input that. So at the top, cost, send email is equal to required. Here we go one folder up, Config Amazon SCS. Save this and send the request again. Again, I get error. Don't get panic. Let's check. It is validation error. So as we know, we just verified our sender email on Amazon SES, but we have to also verify the receiver email for testing the email feature. It is the condition of Amazon SES for testing sandbox account. If we move to production and paid plan, then we will send email to anyone without verifying their email. For testing environment, we need to verify the receiver email. So let me check which email I use for user account in the Mongo DB Compass. See, this is email. So here, I have to add it in our user identity. So search Ss like this. Go to identities. Create identity, select email, and we here your email which is available in your database. Create identity. They again send the verification email on this email. So I open that email here and open this link. See, we get congratulations. Good. Let me refresh this page. See, it is verified. So let's die again. Send the request still, I get Sandymil is not defined. Let me check in the Amazon SS file. Oh, at the bottom, I forgot to remove this parenthesis. I added to show you error, and I forgot to remove that. Save this, and let's send the request again. See, here we get the reset token. But if we check our terminal, see, here we still get one validation error, Amazon SS error, email. Let's check SandymlFunction. Okay. Here in the destination, we have to change these two address to two addresses plural. Now let's try again. Here we get our reset token. Now let's check our terminal. Here we get a new error. Email is not verified in this region. But why as we know, we already verified our email. Still, we are getting this error. Let me explain you. Here I verified our both email in the wrong region. Let me also check on Amazon website. See, here I have Europe region selected, and in my NV variable, I pass Mumbai region, and that's why I get this error. I select here this umbi region. Now I have to again verify both emails in this region. Go to identities, create identity, select here email, write the email and create identity. Now let's verify this from email good. Now I have to do the same for another email, if I eat and done here both emails are verified for my region. So now let's again test our implementation. Send the first API call. See, we get reset token. And also, if we check our terminal, then see here we get emails sent successfully, and we also get message ID. And if I check my email inbox, here I get the email in the spam because here we are in the tasting mode and we also not verify domain. In production, you have to do little changes in the setting and your email will not go into spam folder. This is the power of Amazon SES. I know setting this SES account is little bit difficult and boring part. But for better smooth experience like this, we need to pass from that sweet paint. Now user can open this front end link and then front end will call our second API. That's the job of front end. Also front end developer you whether you are a link. Don't worry about that. Now, also, if we have to use Amazon SES for production, then we need to request for production access. If we check our current status on GetSet page, see currently, our status is sandbox which means testing. Here we can read the mention in the cards below, verify an email address and sending domain to request production ces which enables you to send email at a production level and leverage the full capabilities of SCS. For production, you have to verify sending domain from here. And if you provide write information and submit a request, then AWS usually approves it within 24 to 48 hours. After getting approval, we can send email to email address. Also, I will give some more information in the article below this lesson. So for production, you can read that. Okay? So that's how we send email in most secure, super fast, and cheapest Amazon SS way. 166. Sending Emails for FREE: Let's see how we can send email using SMTP way, which is free, but it has daily limit. We can send only 500 emails from GML SMTP, and if you use YahooSMTP, then we can only send 100 emails per day. But for your local application or college project, this is okay. Also, if you implement Amazon SS and it is working for you, then you can skip this lesson because we will add only sending email features in this lesson, same as we have done in the previous lesson. Now let's see the SMTB implementation. I divide this implementation in three simple steps. Step one, we will implement SMTV configuration in the node application. Then step two, we will generate a password for SMTB last step three, we will test this implementation. Let's start with step number one. For implementing SMTP, we need package called node mailer. NPM install Node mailer, at the d 6.10 0.0 and hit Enter. Good. Now here in our project, create a new folder called config, and in that folder, we will create a new file called SMTP dot js. Good. Now to start configuration, we need one node mailer method from the package. Sconst node mailer is equal to require node Mailer. And after that, we need to create transport for setup. So nodemler dot Create Transport. And inside this, we have to pass the configuration object. Here, we will add properties, and most of their values we will pass in the ENV file. So host to process dot nw dot SMTP Underscore host. Second, we need pot to process dot nw dot SMTP Underscore POD. After that, secure to true. This value is true for only put 465. For other pots, we need to use false value. After this, we pass of to object. And here we need to pass user to process dot nw dot SMTP, underscore user. And after that, pass to process dot w dot SMTP, underscore pass. Don't worry, we will pass these values in just a minute. Now for sending the email, we create a new function called Send SMTP, email is equal to error function. Now in this function, before writing the code, it's better to add try and cache block. And in the cache block, we will pass console dot log. Error in sending email and simply addheemail. Now in the dri blog, we add cost. Mail options is equal to object. Here we pass some options. From two process dot nvt SMTP underscore user, then we have two property. Here, we have to pass receivers email. But here is one question. How can we get the receivers email in this function? Right, we will get it from the parameter. So we addre too. Also, here we need subject. This is the subject of our email and also we pass text, which is the body of the email. Now in the options, we add two to two, subject to subject, and text to text. So we have options ready. Now we just need to send the email. Await, and here we need transporter, which we get from this node Miller method. So let's store it invariable called transporter, and in the send mail function, we use transporter dot send mail, here we have to add mail options. This expression will written the response, so let's store it in variable called response. At last, we simply console dot log, email sent successfully, and we also add message ID, and we adhere response dot message ID. For sending the email, we just need to call this function and pass these arguments. We export this function using module that exports is equal to send SMTP email. Save this file, and now in our request reset API, we will simply call here, send SMTP email function, see atoiput works. Here in the previous lesson, I created these two variables, subject and text. You can copy that and simply in this function, pass user dot email, which is the receiver email, comma subject, and text. Now let me comment out this previous function for Amazon SES. Here our step one is done. Now let's move to step two, which is defining environment variables. So on ENV files in the previous lesson, I added these four variables for Amazon SES. If you don't apply that, then don't worry. Now here we pass four variables for SMTP. If you don't remember their names, then you can simply copy it from the code. Nothing wrong about that. So first, SMTP and ace host is equal to here I am using GmlHst so I write smtp.gmail.com. After that, SMTP underscore port is equal to 465. Here, if you are using Yahoo or Outlook, then you can use the post and port values. But Gmail is good for SMTP. Now we need SMTP underscore user, and here we pass the email from which we want to send email. This is the company email ID. So here I add my email ID. I use this email just for demo, in the future, I will not use it. Now we just need to pass SMTP underscore password is equal to here, we can pass our Gmail password, but after 2024, Gmail don't allow this type of setting. So instead of passing real password, we can pass a password. Let's see how can we generate a password. So open up google.com and go to manage my Google account. Here we go to the security. Now for generating the app password, there is one condition. In our Google account, two step verification must be unable. If it is disable for your account, then you must enable it. Otherwise, you will get SMTP error. Now, after you unable to step verification at the top, search a password and open the a passwords in security. It will verify you first, good. Now it app name. Here we can write node, Miller, SMTV or any other name, it doesn't matter. Only thing is in the future, if you want to remove this app password, then you can remember that app name. Now click on Create. See, here we get 16 digit password, simply copy this and also you can take screenshot or click Photo in your phone because once we close it, then we can't see the password. Copy this and paste it in our ENV file. Make sure you leave the space as it is. Don't change anything in this. And that's it. Here, our step two is done. Now let's move to step three, which is testing. So before testing, make sure you pass the valid email in your user's data. If you don't pass your email, then you can modify it from the Mongo DB Compass. Okay. Now open Postman, and here we send first request, reset password API. See, here we go reset token, and if we check our terminal, we get error. Connect, icon, refuse. Maybe this is error for one time password. So let me try again. Still, I'm getting the error. So let me create another app password for nodemiler, SMTP, create and copy this and make sure you click Done. Now in our ENV file, replace the password, save this file. Now let's try again. Send the first request. Here we get token and in the terminal, see, we get email sent successfully, and we also get message ID. And if I open my inbox, see, here I get the new email. That's so simple to send email from node application. To sum up, you can use Amazon SES for enterprise type application, and if your application is small, then you can use SMTP method, but it will only give us 500 emails in one day, it's totally up to you which one you choose. 167. Follower and Following Logic: Nowadays, in any social media application, there are follower and following feature is must. So let's also implement that in our application. You might get a little scared by this feature if you are implementing it for the first time. But trust me, it is really simple. So let's first understand the logic of follower and following. So here are, which is the login user in our application. And here is another user, let's say Harley and his profile status is public. Now, you want to follow Harley, so you press the follow button. Now what happened in the back end? First of all, for every user, we will add three new fields in the user's schema, followers, which is the array of users who follow that user. Here we add user IDs as reference. Next, we add following field, which is the array of user who is followed by this user. At last, we add follow request, which is also array, but in that, we will add all users ID who sends requests to follow the user. We will add user ID in this follow request only if user account is private. Now back to our example, suppose you want to follow Hurley and Hurley account is public. First of all, your user ID will add in the Hurley follower list. Then Halley's user ID will add in your following list. Very simple. Now here, Halley's account is public. What if we set his account to private? In this case, we can't add your user ID in the Halley follow list. In this case, we will add your user ID in the Hal's follow request array. Now Hali has two options. He can accept the request or reject. If Ali rejects, then we simply remove your user ID from the alisFollow request. Now, what if Hali accept the request? Then first, we remove your user ID from the request list and add it in the follower list. And also, we add Hale user ID in your following list. So that's how simple this follower and following features. Now in the next lesson, we will define AEI for these features. 168. Follow the User: Now let's define API for adding follower. As we know, the logic is very simple. So let's quickly implement it. Here at the bottom, we add router dot post endpoint to forward slash. Here, we add user ID, so Column user ID slash follow. This is the user ID of the user who we want to follow. Also, we need logged in user ID, so we add here orth middleware and acing function with request and response. Now inside this function, first of all, we get this user ID, so Const user ID is equal to request dot Perms dot user ID. Also, we need const, current user ID equals to request dot user dot underscore ID. First of all, we will check one condition. If user ID equals to current user ID, then we return response with status code 400 for bad request dot Json Object, Message property. You can't follow yourself. First logic of follow API is we will check other user account is private or public. For that, we get to user information. So cons user to follow is equal to await user dot fine buy ID. And here we pass user ID. Next, we pass your condition. If user to follow is not available, then return response with status code 404 and Json to Object with message property, User not found. Also, we need to find current user info. So const current user is equal to await user dot Fine BD and pass here current user ID. And also pass here, the same condition, so duplicate this condition by Alt plus sift plus down arrow or Option plus sift plus down arrow and move this line below withholding option or alter arrow keys. And here we just change this user to current user. Now after we get the both user, we can pass your condition if user to follow is private. If this is true, which means account is private. I account is private, then we need to add current user ID in the other user follow request. But for that, we need to add three fields in our users schema. So on user schema, at last, we add filled followers to array, and inside that, we add object type to Mongoose dot schema dot types dot Object ID, and ref to user. Also, we need following and follow request, which has same schema type and user reference. Just here we change following and follow request. Save this file, and back to our route. Here, we write user to follow, dot follow request, dot push. And here we add current user ID, and then we can await user to follow dot save. And here we return response with JSON message. To follow, request sent. Good. But here's one thing. It might possible user is already available in the follow request array. Before this push method, we add condition I user to follow dot follow request dot includes here, we pass current user ID. If current user ID is available in the array, then we return response dot status, 400 dot Json Object with MsatPperty to follow request already sent. And after that, we add s, and we can move this part in the s block. So here we write the logic of adding follow request if account is private, but our other user account can be public. After this, if we add Ls, if you are getting confused, then you can write commands for that. I write comment here, logic for public account. Good. Now, what do we want to do if account is public? Right, we will direct add current user ID in the follower list, and in current user following list, we will add user to follow ID. User to follow dot followers dot push. Here we add current user ID, and after that, current user, dot following, dot push. And here we add user ID. And after that, we save these both documents. So await user to follow dot save, and await current user dot save. After that, we return response with JSON object with message property, user followed successfully. Now as we did previously, it might possible our current user ID is already available in the follower list. We pass your condition before this logic. If user to follow dot followers, dot includes here we pass current user ID. If it is available, then we return response with status code, 400 for bat request, and in Jason object with message property to already following the user. After this, we add s, and we will move this code in the se block. That's it. It is really simple. Now let's test this implementation. So for testing the follow API, we need another user account. Let's create this first, open created user API, change username, let's say, Hurley 001 and email to Hali at the red gmail.com. Also, I will remain password the same. Otherwise, I will forget the password and send the request. See, here we get the new user token. Here we need this Hurley user ID. So per Mongoi we compass, go to users and copy this new user ID. Back to Postman for follow, we create a new request. Follow API, SDB method, to post, URL to SDDP, Column double forward slash Local host, Column 3,000, slash API slash user slash here we page the new user ID, slash follow. We need the current user token, so we go to the login API, change the password because we change it in our previous lesson and send the request. Copy this token, and in our follow API, we go to headers, adhere authorization, and in the value bearer, space pace the token. And send the request. See, here we get user followed successfully. We directly followed the user because that new user account is public. Now, let's also taste by making that account private. So we go to the Mongo Di becompasRfresh the data. First, we remove the ID from the following list. And also we remove ID from the follower list and also make this new user account is private to true and update it. Now, let's back to follow API and send the request. See here we get follow request sent lovely. Now in the next lesson, we will create API for accepting the follow request and rejecting the follow request. 169. Accept the follow request: Let's define API for accepting and rejecting the follow request. First, we will implement rejecting the request because it will be easy to test, so router dot post and point to slash reject Ds request, slash and here we need the requester user ID. Call requester ID. After that, we also need the orthomddal ware. We add a sing calve function with request and response. Now, first of all, in this function, we will get Cost, requester ID is equal to request dot Perms dot requester ID. Also we need const, current user ID is equal to request dot user dot underscore ID, which we will get from this Omdalware. First of all, we will check if both users are available in our collection or not. Remember, we did the same in the previous API. Here it is, copy this code. Also, copy this first condition for same ID, and at the bottom, paste it in our reject API. Here we need to do little changes. So at the place of user ID, we have to add requester ID, and here also requester ID. And also, we need to change this variable name so select user to follow, press F two and change this to requester user. Will give us more clarity. Now for rejecting the request, we just need to remove requester ID from the follow request array. But before that, we can check whether we have requested ID in the follow request array or not. So if current user dot follow request dot includes requester ID, if this condition is not true, we pass here exclamation mark, and then we return response with status code 400 and dot JSON Object with message property two, no follow request found. And I follow request is found, then here we can use filter method for removing requester ID from the array. So Const, updated request is equal to current user dot follow request dot Filter. Here we add ID, which is the individual item of this array arrow function, and here we return condition dt two string not equals to requester ID. This will remove the requester ID from the follow request array. We can simply set current user dot follow request is equal to updated request. And then we await current user dot c. And at last, we simply return response with JSON object with message property to follow, request, rejected, and that's it. Now let's test this API. So open up Postman, and here we add a new request called rejecting the follow request. Now in this, we set API method to post and point to SDDP, Column double for slash, local host, Column 3,000 API user slash reject request slash here we need to pass the requester ID, which is the ID of the user who sent the request. Here we open Mongo Db Compass, and can you tell me which user send a request? Right, it is our first user, which ID is added in the follow request array of another user. So copy this ID and paste it in the URL, and we send the request. Oh, we need to pass JWT Token. Now here we need token of the user who getting the request, which is our new user. So in the log in API, I change the user name to Hurley 001 and also change the password and send the request. Copy this token. And in the reject API, we go to headers, adhere authorization, and value to bearer space, pace the token. Now we send the request. See, here we get follow request rejected. As if we check our database, refresh the collection. See, for the second user, we don't get any ID in the follow request. Here, our rejected API is working well. Now we can define API for accepting the user request. This API is very similar to the rejected request API, so we copy whole API and paste it below. Good. Now here, first we change the endpoint to accept as requests requester ID. After that, if we accept the request, we also need to remove requester ID from the follow request array. So we keep our code as it is. But after removing the requester ID, we need to add the requester ID to the follower list. That means we are accepting the follow request. So before the save method, add current user dot followers dot push. Here we push requester ID, and also we need to add the current user ID in the requester users following list. So requester user, dot following dot push. Here we push current user ID. Now let's also await requester user dot save. At last, we change the message to follow request, accepted, and that's it. Now let's also taste this API. So back to Postman and here we need the same request like reject. So we can duplicate the taste API from here, change the name to accept the follow request. Also endpoint to accept as request requester ID. And if we check the headers, see, here we also get that token, and that's why we duplicate this test. Now, let's send this API request. See, here we get no follow request found because we just rejected the follow request. Here we need to send the follow request again. For that, we go to follow API and send the follow request. Request sent, good. Now back to accept request API and send the request. See, we get follow request accepted, and if we check our database, refresh the collection. See, here we also get user ID in the follower list and request our ID removed from the follow request. And here we get the ID in the following list. 170. Exercise - Getting the list of Followers and Following: Now it's time for little exercise. In this exercise, I want you to create two APIs. One API for getting the user's list of another user, and second API for getting the following list of another user. If you are user one, then you can send request for getting the list of user two, followers and following. Here our API look like this. Slash API user ID, slash followers. Slash following for following API. Think about logic first and then implement it. It is really simple. I know you can complete this exercise. Try to solve this and then what's the solution. I hope you complete this exercise or try to solve this exercise. Appreciate yourself for that. Now let's see the solution. So here we add router dot Get and point to slash Colin user ID, slash followers. This is the ID of the user whose followers list login user wants to see. So we need middleware and then asing callback function with request and response. Now inside this function, first, we get cost user ID is equal to request dot Perms dot user ID. Also, we need cost, current user, is equal to request dot user dot underscore ID. Now let's understand the logic of this API. Should we show followers list of any user no. You can see only those users followers list, whom you follow or whose account is public. Here, we need current user follower list and another users is private property. Again, we copy both users code from the previous API and paste it in this API. Now here we change the variable name to user and change this requester ID to user ID. Good. Now, after this, we can pass condition if user dot followers dot includes, here we pass current user ID. Or user dot is private is false, which means user account is public. If any of this condition is true, then we will show users followers list. Return response dot Json, and here we pass user dot followers. We add, and in that we will return response dot Status 400 dot Jon, pass your Object with message property, Gant, Get followers list, account is private. Now let's do this implementation, save the changes and open postman. Here, we create a new request called Getting Users followers list. Here we add URL, SDP, Column double four slash, local host, Column 3,000, slash API, slash user ID, and at last, we add slash followers. Now back to Mongo DB database, copy this second user ID, which has follower and paste this ID in the URL. Now in this API, we need to pass token. So go to headers. Here add authorization and value to bearer space. And here, we have to pass another user Token who is following this user ID. So back to login API, and here we simply login with old account, change the password, and send this request. See, here we get token, copy this and paste it in our API header. Good. Now send the request. See, here we get the array with the follower's ID. But as we know, in the real world, we need to show user name, so we need to populate it. For that, in our fine query, we had populatet method at first, we pass fill name which we want to populate, which is followers, and then we pass fills name, which we want to get from the reference, which is underscore ID and user name. Now here is one thing. Here, we populate the followers list. So now it is not same as before. It will be array of object with underscore ID and username fields in each object. So we can't pass here, this includes method. We can use Fine index method which we use in the previous projects, and also write here different condition, current user, dot following dot includes, and here we pass user ID. So if current user is following the other user, then we can also get those followers list. Save the changes and take a look. Send the request. See here we get the follows list with ID and user name. Now, let's create another API and you guessed it correctly, we will duplicate this API and at the bottom, we add it here. Now here we need to only change little things. So first of all, we change the endpoint to slash user ID, slash following. Then here in the user's query, we need to populate following field, then this condition will be the same and we change the message to following list, account is private, and it's done. Now in the next lesson, we will define API for unfollow the user. 171. Exercise - Unfollow the User: Let me give you another exercise. In this exercise, you have to create API for unfollow the user. So our API endpoint will look like this. Slash API user, slash user ID, slash unfollow. It is really simple, spend some time and solve this exercise. And after that, come back and watch the solution. Now let's quickly see the solution. So here we write router dot Post and 0.2 slash Column, user ID, slash unfollow. Also, we need Omidleware ACN callback function with request and response. Now here we need to find both users. So copy this starting code with both these conditions and in our API pass this code. Now here we don't need this populate method, so we remove that, and also we change this user name to user to unfollow. Good. Now after getting the both user, we pass your condition I user to unfollow dot followers, dot includes current user ID if it is not true, and here add exclamation marks, and then here we return response with status code, 400 and in Jason, we pass Object message to user is not available in the followers. And after that, we can remove current user ID from the user to unfollows followers list. So user to unfollow Dart followers is equal to user to unfollow Dart followers dot filter method. Here we get each ID, and here we return condition ID, dot two string is not equal to current user ID. Also, current user, dot following is equal to current user, dot following, dot filter. Here we get ID arrow function, and ID two string is not equal to user ID. Now we can save both documents, await user to unfollow dot c and await current user dot C. And here we return response dot Json object with message property, user unfollowed successfully. And done. Now we can taste this implementation. So one Postman and here we duplicate this follow API. Change the name to unfollow API. Now let's change the endpoint to slash user, slash ID, slash unfollow, and send the request. See, here we get success message user, unfollowed successfully. So that's how we implemented followers, following request and reject API. You can see it is really simple. We need to understand logic before we implement any new features. 172. Section 14 - Introduction: Welcome to the 14th section of the ultimate no JS course. In this section, we will implement post related features like posting a new image or video, displaying post, delete the entire post. Also, we will add like and unlike feature writing a new comment on post, replying the comments, and much more things. This is one important section, so let's start this section. 173. Create Post Model: Let's first create post schema before creating APIs for post. In the models folder, we create a new file called post dot js. Now go to the user's Module file, copy all code from here and paste it in the post model file. Now, first of all, let's remove this schema object and As we need to change some name here. Se like this user schema and renam this by F to post schema and hit Enter. Now select user, and for selecting multiple times, press Control plus D or Command plus D and change this to post. Now we have to only add Schema object. In the post document, we need couple of things. First of all, we need user, which is the user ID who posted image or video. So type to Mongos dot schema dot Types dot Object ID, ref to user, and required to true. Next, we need media. It can be image or it can be video. Also, it can be one or more than one. So we add here array, and in that, we add object, first property name to object, type to string, and required tou true. And another property, media, type to object, type to string. Num to array, here we add image, or it can be video. As we make it required to draw. By this schema, we get proper understanding about media. Next, users can add caption with the post, type to string and dream to true for removing white space, or we can also remove this stream property. Users can add any types of captions. Also, we are not making it required because user might don't like to add any caption. After that, we add s, which is array, and also here we stood the reference of the user. So we copy this type and ref property from the user field and paste it here. Good. Now let's add some additional fields like texts, which is also array, type to string. Next, we also add location, type to string, and that's it. Currently, we need these fills. If in future, we need some other fills, then we will add it in the upcoming lessons. Also, we will add comments fill later in this section. So don't worry about that. Now let me show you one thing in the schema object. Previously, remember we had created at fill in our project. But in the Mongo schema, we can automatically add that. Simply after this schema object, we had second argument in schema method, object, and here we add timestamp property and we set it to drew. By this property, we will get two time related properties, created Ed and updated This is the current time when the document was created and in updated ED, we will get date and time of last update. Don't worry, we will see that when we create new post and we will do that in the next lesson. 174. Create a new Post: Let's create an API for creating new post. In the routes folder, we create a new file called post dot js. Here, we need Router, Cost Express is equal to require Express. And after that, cost Router is equal to express dot Router. At the end, we simply module dot exports is equal to Router. Now let's set this router in our main file. So in index dot js file, we add cost post route is equal to require. Here we go to routes folder, and in that post. Now at the bottom, app dot g, prefix to slash API slash post, and at the second argument, add post routes. Save this file, and now we can add post routes. So in the post file, we add Router, which method we will use, right. We will use router dot post. Here we add forward less for creating new post. Also, here we need orthomidal ware because we want only log in users should create a new post. And after that, we add AC callback function with request and response. Now what we want to do in this API want to simply create a new post document, and store that images and videos in our local server. So for that, we need to set up Multer same as we've done previously. So pen up terminal and write and pm install Multer at the red 1.4 0.5 dash LTsO. Eight, Enter. Good, minimize this terminal and let's implement Multer. So in the previous project, we added Multer config in the same route file, but that looks little unprofessional. So in this project, we can configure Multer at different place and then import it in this file. Okay? So in the config folder, we create a new file called MulterUload dot js. We know implementing Multer is really simple. Just we need to set the file name and we can set the file filter for preventing unnecessary files upload. Cost, post upload is equal to Multer and inside this, we need to pass configuration object. First, we pass storage, which will take care of the file path and file name. So at the top, we create separate variable const storage is equal to Mltert disk storage. And in this, we also pass object with properties. Also, we need to input Multer at the top. So Const Multer is equal to require from Multer. Good. Now in this object, we add first property, destination. And here we get request, file, and CB has parameters, error function, and inside this, we simply call CB function. And at the first position, we have to pass error, which is null. And at the second argument, we pass the path, destination of our post files. Let's say uploads post. Next we have file name, again, arrow function with request, file and CB and inside this, we will define specific and unique file name, same as we did previously. You can also see code from that project. It's totally fine. So Const timestamp is equal to date dot now. By this, we get current time. After that, we on to remove some character and spaces from the file name. So cost original name is equal to file dot original name. By this, we will get the original name of the uploaded file. Now in the file name, there may be some space, so it's better we replace that space with the dash. It will make the file name URL friendly. We add dot replace method. Here, we first add regular expression is a syntax of regular expression, which is double forward slash between these, we write backward slash a for space and plus for one or more white space. At the end of the regular expression, a G for global flag, which makes sure all matches in the string are replaced, not just the first one. Now, here we pass dash in single codes. This means all space will replace by dash. Now, what if in the filename, we also get the special characters? We need to remove them as well. We add another replace method. First, what we will pass? Write regular expression by double for our slash between these, we write regular expression for getting the spatial characters. Here we add A to Z. Also A to Z zero to nine dash. Now we want to get other characters which are not part of these characters. It will be our special characters. So to inverse this, we wrap it in the square brackets, and after the first square bracket, we will add Garret for inverse, and at the end, we also add G for global flag. Now we want to replace these special characters by nothing. We just want to remove them. So we adhere only codes without anything. Now at the end, we will mix this time stamp and original file name. CB first, we pass null for error, and second, we write taxes. Here, we add Cali brackets, time stamp, dollar Cali brackets, original name and done. We define destination and also file name for our uploaded file. Now we can simply pass this storage variable here in the multi function. Now after storage, we pass file filter in which we will filter files by their extensions. So cost file filter is equal to error function with three parameters, request, file, and CB. Here we will check while is valid or not. So Const allowed types is equal to array, and here we add file types. Now, in our social media application, user can upload images and videos also. We add here image slash JPEG, another image, PNG. Next, image GIF and for video, we add videos MP four. And also video slash MOV. You can also add another types if you wanted. Now we can simply put here condition I file Mme type is from these types, only then we will allow it, else we will reject it. If allowed types dot includes file dot Mme type, it is true, then we call this CB function and first, we pass null for error, and then pass through for accept the file. Now, if MM type is something else, then these types, then we adhere condition and call here CB function. At the error, we pass new error, and here we pass the error message, invalid file type, only JPEG, PNG, GIF, MP four, and MOV are allowed to reject this file, we adhere pause. Now we can simply pass this file filter in the Multi config object. Also, in the multer, we can specify the file size using Limits property. For social media, we can set limit to 15 MB. I user wants to upload some videos, then they can also do that. Object file size to 15 into 1024 into 1024. By this, we get the bytes value. This is the limit for each file. If we use it for uploading multiple post, then each file has maximum limit to 15 MB, not for combined limit, and done. Here, our post upload method is ready, so we can export it from here. Module dot exports is equal to post upload. Save this file, and in our routes file, here after this orth middleware, we add post, upload, see auto input works dot because we want to upload multiple images in the post. Now with the first position, we write the input fill name. Let's pass here media. From the front end, we need to take file in input with fill name media like this. After that, we will pass the maximum number of files, let's say ten, and that's it. Now we can write API logic. First of all, here we check user uploaded file or not because if there is no media, then we don't want to save the post in our database. I request or files are not available, or request dot files dot length is equal to zero. If any of these conditions are true, then we return error, response, dot status, 400 for better request. And in the JSON, we add object with messed property. At least one media file is required. Now, if media is available, then we store that post in our post collection. So cost, new post is equal to new post Great auto input works, and here we need to pass fills. First one is user to request dot user dot underscore ID. Next, we have caption, which we will get from the request body. Above this, we con destructure the request body, and here we get caption. Also, user can add text and location. Now, in our post, we add caption to caption, or we can also remove this text to text and location to location. We need only one field which is media, and that is array of object, and that object has two properties, name, which is the name of the file and media type, which is image or video. By that, when we display that media on front end, then we can easily decide which tag we should use. So here we need to create that array of object. It is really simple Cast media is equal to request dot files dot map. Here, we get the single file in the parameter, error function, and here we want to simply reten an object. Here in the Gully brackets, we are written object, name to file, dot file name, and for media type, here we need to pass condition. File dot mime type, dot starts with double codes, image. If it is true, then we set type to image, column, else, we set it to video. This method, we will get media array of object here in our new post, we set media to media. After that, we can simply await new post dot C. Then we return response dot status to 01 for creating new data. Dot Json object with message property, post uploaded successfully. As we return a post to new post, and that's it. Let's test this implementation. Save this file and open postman. Here, we create a new folder called post, and inside this, we add new request upload a new post, change the SDDP method to post and URL to SDDP. Column double for slash Local host, Column 3,000 slash API slash Post and send the request. See, here we get token required, go to login API and simply generate a new token. Copy this in our new API, we go to header and add here new header, authorization to beer space, and here we paste our token. Now send the request. See, here we get at least one media file is required. Now let's also add media file with this request. Remember from which section we can send file, we can send file from the body and form data. Here in the key, we pass media because in our API, we define media here in the multer method. Now here we select file. Add a new file from the local machine. Let's send any two or three images from here and send the request. See, here we get error, no such file or directory aploadsPost. Basically, they are telling us we need to create folder path. In our server, we create a new folder called uploads. Make sure you use only small letters because it is case sensitive. Now in this uploads folder, we create another folder called Post. Good. Now send the request. C, post uploaded successfully. Here we get new post object with user, Media also looks great with name and media type, likes and tags to empty array and we also get timestamps created at and uploaded at. We get this both because in our schema, we addre timestamps to true. That's how we create a new post. Now in the next lesson, we will get post from the post collection. 175. Getting current user posts: Now it's time for little exercise. Here, you have to create a new API for getting all post of current logged in user. Also in that, you have to implement pagination feature, same as we did in the previous project, products API. Make sure you display the letters post first and then older. I know you can do this, give it a try and after that, what's the solution. Now let's quickly see the solution. So here in our post route, we add another router dot GdndpoEndpoint, let's say, slash my post. Here, we also add Osmidalware and ASN callback function with request and response. Here we need to get for squary parameters, which will give us page and limit. Second object is equal to request dot query. And here we get page and limit. Also, we can set the default value of this page and limit. So page to one and limit to let's say ten. If in the query parameter, we pass something else, then it will replace these values. Also, as we know, when we get values from the query parameter, those values are string, so we need to convert them into integer. So here at the place of cost, we write let, and after that, page is equal to parse integer, page, and after that, limit is equal to parse integer, limit. Now we can add query for post. So const, post is equal to await, post dot find. Here we pass Object user to request dot user dot underscore ID. And here we add Skip method. That page minus one into limit, and also we are limit method, and we pass here this limit, and also we'll make this line. And then at the end, we simply return response dot Json and pass here this post. Now let's tase this implementation. Save this file and open postman. Here, we duplicate this request, change its name to getting logged in user post. Also change the method to get and URL to API post slash MI Post and send the request. See, here we get the post. Currently, we have only one post, and that's why we get here single post, so it is working. Also, to improve this query, we can do one thing. Pass variable, which tells our front end there next page available or not. It is really simple. So here, after we get our post, we create a new variable called a next page is equal to here we pass condition if this post dot length is equals to current limit, then it possible there might be a next page for post, so we pass here true if current post size is less than limit, then in else, we pass false. It is really simple logic. Now in the response Json, we have to pass object, post to post. Page to page, limit, to limit, and as next page to hass next page. Save the changes and take a look. Send the request again. See, here we get post, and if we scroll down, we get a next page to falls because current page limit is not full. Now in the next lesson, we'll see how to get post for our social media homepage. 176. Getting Home Feed: Let's create API for getting post, which we can display on home screen when user open our application. Here we add another router dot GAD and point to slash following because on homepage, user will see post who followed by her or him. Here we also need Osmidleware because we need current users following list and also acing callback function with request and response. First of all, in this API, we need to find the following list of current user. Seconds user is equal to await user, dot fine by ID, and here we pass request dot user dot underscore ID. Here we only want following fill, so dot select, and we pass here following in codes. Here we get three lines, which means auto input did not work. Let me input this user model at the top. Cost user is equal to require. Here we go one folder b models and go to users. Good. Now for post query, we can define separate variable. Let query is equal to object. Inside this, we pass user, and here we again add curly brackets. Now we can use Mongo Deb operator called $1 in, which is used to check item value from the array. Here we pass user dot following, which is array. Basically, this means so post of users who are available in the user dot following array. Now from this, we can simply get post, so Const, post is equal to await, post, dot find, and here we add our query. Also, with this, we need to populate the user who uploaded those posts. So dot populate and here we pass user filled at the second parameter, we pass which fields we want. So score ID, user name and profile name. If we have profile picture, then we can also populate that here. Next, we will add short. Here we pass object with created at property, and we shot them in descending order, so pass minus one. By these, we get new post first. Currently, we didn't implement pagination feature in this query, but in real world, we need pagination feature because in real world, there may be hundreds or thousands of posts. At that time, we can't send all post in single request. It will make our server slow. So here we need infinite query feature at the top, add let object is equal to request dot query, and here we destructure page is equal to one, and limit is equal to ten. These are default values. Also, we need to convert them in integer. Page is equal to parse integer to page and limit is equal to parse integer, limit. Now in our query, we add Skip method and pass here page minus bone into limit. And we also add limit method, and we pass here limit, and also at the end, we add len method. Now, everything is great, but here is little issue in this API. Let me explain you that with the example. Suppose here we have 20 post and our user send API request for post. Our API send this first ten post. Now when user is watching this post, it might possible any following user can add new post in the database. Suppose any five following users upload five new post. Now when current user want to see more post request with page two query parameter. At that time, our query will skip first ten data from the database because page two and display this post. Here we can see duplication of post because this five post added recently, and this is the issue. Now, what is the solution here? We can use here cursor based pagination. Let me explain you in simple words. Cursor based pagination means we will fetch post based on the time. For example, here is user h he is on the homepage and send requests for first ten post. Now, from the back end, we will send ten posts and also we will send last post created at time. Now when Harley wants another ten post, then he will send that last post created at time, which we called as cursor. Now you might ask why we need this cursor. We will use this cursor in our query. Find another ten post whose created time is less than this cursor time. By this, we don't get duplicate post, and also our pagination will work smooth. This technique is called as cursor based pagination. This technique is used very often when the data we want is adding very quickly like social media. Now let's implement this in our query. First of all, we will return the cursor in the response so you will understand it properly. Here after our query, we add cost next cursor is equal to. Here we pass condition, post dot length is greater than zero. If it is true, then we return last post created at Tate. So post, square bracket, post dot length minus one. By this, we get the last post, dot created at, we return null. Now at the end, we add response dot Json here we add object, post to post, and next cursor to next cursor. Good. Now, let's add this cursor in our query because that is the reason we are sending this cursor. So when we send this next cursor to front end, our front end will send this next cursor in the next post request. So in the body or query parameter, we get the cursor which sends front end. And now we simply add this cursor in our query. Here query created at is equal to Coli brackets. Here we pass Operator dollar LT, which is the less than, and we pass here new date. And here we pass cursor. Now here we need to handle burn situation. First post request, there will be no cursor. So we pass here condition if cursor is available, only then we add this created in the query. So without cursor, our query will look like this. And with cursor, our query will look like this, simple as that. Also we can pass here has next page property. So copy this line from the previous API and paste it in our API. And at the end in response object, we add hasNext page to hass next page. Now, let's t this implementation. Open Postman, duplicate this last query. Change its name to getting following, post. Also, we change the URL to API post slash following and send the request. See, here we don't get post because our current user has uploaded the post, not any of his following. So here we need to add another user token. Go to Login API, log in with another user account. What is the user name and password of another user? Let me remember yeah, it is h001 and password is set to 128. Yes, get this token, copy this, and in our current API in the header, we replace this token and send the request. Still, we don't get post. Let me check who follows whom. Oh, here, no one follow anyone. So to make this dic, I copy this current user ID, which we logged in and dits ID in the followers of previous user. And also copy this user ID and d it in the current user following list and update it. Now, let's send this request again. See here we get post, and also we get next cursor, which is the created at date of the last post and has next page to falls, this means it is working properly. 177. Deleting the post: Let's create an API for deleting the post, so Router, dot delete, and here we add forward slash, column, post ID, which is the query parameter. Also, we need of middleware because only authorized users can delete their post. And last, we add ASN callback function with request and response. Good. Now, first of all, in this function, we get const post ID is equal to request dot PRMs, dot post ID. Also, we get cost userid is equal to request dot user dot underscore ID. Now here in this deleted API, we warned only user who created post can delete the post. So for that, we need to find the user of this post. Cost post is equal to await post dot Fine By ID. And here we pass post ID. We pass condition I post is not available, then we return response with status code 404, and in Jason, Object, message property two, post not found. Now, what if we found post? Then we have to check current login user is the author of this post or not? So if post dot user, which is the object ID to sring is not equals to user ID, then we again return response with status code 403 for unauthorized error in the Jason, we add object with message property unauthorized to delete this post. Now, what if user and author is also same? In that case, we first need to remove the images or videos of that post, and then we can delete the post document, right? So here we need to run for each loop because our media is array, supposed dot media dot for each. Here we get single file object, arrow function, and here we run our logic for each file. First of all, we need the file path of the image or video because by that only, we can remove that file. It is really simple. For path, we need path module. So Const path is equal to require path, which is the inbuilt module of node. Now at the bottom, cost file path is equal to path dot join. First, we add underscore underscore Dname and also comma we add file dot name, which is a name property in media. I'm not sure about this path. So let's consult dot log this file path. And at the bottom, we simply return response dot json, Object with measured property, post, deleted successfully just for checking this path. Save this file and open postman. Here we duplicate this getting logged in users post because in that API, we have token of the user who created that post. Here, we change the API name to delete, the post, change the method, to delete, and in API endpoint, we change that to API post post ID. Let's also copy the post ID from the previous API, send the request, and here at the bottom, we get ID, copy that and paste it in our API endpoint. And send the request. See, here we get post deleted successfully. And if we check our terminal, see, here we get the file path. Ignore the first path because it is underscore underscore, dear. Just to see here, we get slash routes slash filename, which is our current folder path, but we don't want to add routes. So here between Date Name and file name, we add double codes, period, period. Save this file, and let's send the request. In VS code terminal, C, route is removed. Now we just need to add slash uploads post because that is a path of our post. Before this file name, we add slash uploads post, save the changes, and send the request again. If we check our terminal, see here we get our file path. So this is how you can taste the code using Console. I always do that when I'm confused. I just comment out the database logic and then taste the API. By that way, we don't need to create and remove data from the database. So we get here file path. Now we just need to remove that file using file module. We already did that in our previous project. So here, remove the Console and add here, try and catch blog. And in cache, we add console dot error in Batis we pass error in deleting file, dollar Coli brackets, file path, and also log this error object. Now in the drilog we simply await fs dot unlink and here we pass file path. For using await, we need to make this callback function async, and also we need to import Fs from the inbuilt module. So Const Fs is equal to require Fs promises because deleting the file is async operation. And after removing the file from the server, we can remove the post document. So await post dot Delete one because we already fetch post at the top. And done. Save the genes and send the delete request again. See here we can post, delete it successfully. And if we check our Bend files in the post folder, images are also deleted. 178. Like and Unlike the Post: Let's create API for and unlike the post. It is really simple. If in the array, user ID is not available, then in that we add user ID, which means we like the post, and if user ID is already in the L array, then for unlike the post, we just need to remove user ID from that array. Let's add router dot page. Here, we add endpoint to slash column, post ID, slash L. This is the same API we will use for and unlike the post. Comma ORT es callback function with request and response. Now, first, we get post ID is equal to request dot PRMs, dot post ID, and also we get cost user ID is equal to request dot user dot underscore ID. Now, first, we find the post, so Const, post is equal to await post dot Fine By ID, and pass post ID. After that, we check condition. If post is not available, then we return response with status code 404, and in the Jason, we pass object with message property to post not found. Now, if post is available, then we check user already like the post or not. So Const already liked is equal to post dot likes, dot includes, and here we pass user ID. Now based on this, we can pass condition, cost, updated, post is equal to of eight, post dot fine By ID, and update. First, we pass the post ID, and can you tell me what we will pass in the second argument? Right, we pass the updates. So here we pass condition. I already liked is true, then we have to remove the like. So for that, in object, we use Mongo Di Be operator, which is dollar pull to object. And here we add likes to user ID. And if already liked is false, we pass here a and here in the object, we add another Mongoib method, dollar at to set to object, is to user ID. The reason we add here at to set because it will only add user ID if it is not available, it will not duplicate the user ID in s. Now at the third argument, we pass object with new to true. This will give us updated data. At the end, we simply return response dot Json Object with message property. Here, we check condition. I already liked is true, then we pass here, post unlike else we pass post like and also we can return likes to updated post dot likes dot Length. You can return whatever value you want to return from API. Now let's weekly tis this API. One postman, first, we need to create a new post because in the previous lesson, we deleted our one and only post. Go to create post API send the request. See here we get post error, so we have to select images again. And send the request. See, here we get new post, copy its ID. We need that. Now in our post folder, we create a new request called L and unlike the post. Change the method to page, and endpoint to SDDP, column double for our slash local host, Column 3,000 slash API slash post, and here we paste our post ID. Also in the header add authorization key and value to bearer space copy token from the login API and simply paste it in our API and send the request. See, we get post like and likes count to one. Now send the request again. See, we get post like and likes count to zero, so it is working. 179. Implementing Comments Feature: Nowadays, in almost all social media apps, there are features for adding comments on the post. It is the way to engage people for that post. Let's also implement command features for our post. First of all, the question is, where we at the command? We need to add command in the schema. So on post model file, and here at the bottom, add commands, which is the array of object. Now, instead of writing whole schema here, we can create separate schema for commands, and then here we add reference. By that, we don't get confused. So before this schema, we add const comment schema is equal to new Mongoose dot schema, and here in the object, we pass the single comment schema. First of all, we need here user to object, type to Mongos dot schema dot type dot Object ID, and we make reference to user and also required to True. Next, we need text to object, type to string, and we also make it required True. After that, we need created at, which is the time when that particular command was created. So type to date and default to date dot now. Now as we know, in social media, user can reply to other users command. Should we add that reply features in our Linky fi or not? Let's do that also. For replies, we add another filled replies, which is array, and inside this array, we need to define schema for each reply. Don't worry, it is the same as this command. Simply copy these three properties and inside this array, add object and paste them here. Make sure you add it in the object, otherwise, it will give us error. Now we have command schema. We can simply add it at the bottom in the schema see, now we can easily see the post schema without getting confused. Now let's create API for adding the new command to the post. It is really simple. So here we add router dot post and point to slash column, post ID, slash commands. Here, we also need orthomiddal ware and ASN callback function with request and response. First of all, we get cost post ID is equal to request dot PRMs dot post ID. Also, we get Cost userID is equal to request dot user dot underscore ID. Then we also get Const text is equal to request dot body dot text. Before doing anything, first we check if text is not available, then we simply return response with status 400 and I Jason, we pass object with message property to comment, text is required. Now, if we have command text, then we need to simply create new command. So cost, new comment is equal to object, and inside, we have to pass user to user ID and text to text. So we don't need to pass created date because we already pass current date as default value in our schema. Now here we need to pose this new comment object in the post commments array. Can you tell me which method we will use? Yes, we can use here, fine by ID and update. Cost post is equal to await, post, dot, fine by ID, and update. At the first position, we add post ID. At the second position, we need to pass what we want to update. Now for pushing the new command, we use dollar push method. Here we add Cully brackets and in that commands to what we want to push Wt this new command. And at the third argument, we pass object with new to true. Now, can you tell me why we don't use here at to set method? Right, because at to set don't allow duplicate values. But here, command can be duplicate. One user can attributed commands. We can't deny that, and that's it. At the end, we return response with status code 201. New data, and we return JSN object with message property to comment added successfully. And as we can send comment to post dot commands in square packet, post dot commands dot Length minus one, which is the latest command we add and done. Now, let's do this implementation. Open Postman and duplicate this API, change the name. To creating a new command. Change the method to post, and also point to post ID commands and send the request. See here we get error because we don't pass text. In the body, we go to raw and here we add object with text property. What should I comment? Yes, this is a great product. Here you can add any command. Now send the request. See here we get command, edit successfully, and here we also get letters command. Now in the next lesson, we will create API for adding reply to this command. 180. Adding Reply to Comments: Now let's create API for adding reply to specific command. It is very similar API to previous one, so router dot post, forward slash, Column post ID, slash commands, slash here we also need comment ID because in which command user wants to add reply, we need to find that. And after that, slash replies. Scroll up and copy this entire API with OT and paste it in our API. Good. Now we need to change little things here. First of all, in the params, we are getting comment ID also. Let's destructure request dot params, and here we get command ID. Now at the place of new comment, we name this to new reply and at the bottom, we will change the method to fine one and update. As we use fine one and update, we need to pass her condition object at the first argument. Inside this, we pass underscore ID to post ID. And also we pass her condition, double codes, comments dot underscore ID to comment ID. Make sure we write the right property name because it is case sensitive. Also, you might ask our comments is array, and here we are writing comments dot underscore ID, will it work? The answer is yes, it will work because in Mongo Di B, we use this dot notation, which allows us to search through the comments array and find the first object where underscore ID matches command ID. Now in the push method at the place of commans we add comments dot replies. Here we can use comments dot dollar dot rep. Now you might ask, what is the difference between comments dot replies and comments dot dollar dot RPS. So commens dollar operator is optimized for targeting a specific element inside an array. On the other side, comments dot replies is for general field. Let me explain you with example. Suppose this one post has ten comments, and we want to add reply to this second comment. Now if we use here commens dot replies, then it will add reply to all commands. We don't want that, on the other side, if you use here comments dot dollar dot replies, then it will add reply to only the second command, and that's what we want. Always remember if you want to update nested arrays specific item, then you need to add dollar operator between them. Like commens dot dollar dot replies. This dollar is called as positional operator. Short in Mongo DB, dot notation works for searching and deleting elements, and positional operator is needed for modifying array elements. Now here in our update method, we change this new comment to new reply. And also at the end, we change the message to reply, edit successfully, and we simply send that new reply in our response. So above these we add cost comment is equal to post dot commands, which is the array. Now for getting the specific command, we need to find its index. So instead of that, in Mongoose, we have another method called dot ID. This will help us to find a subdcument by its underscore ID field within the array. Just we need to pass here comment ID, but make sure you add comment dot ID is method of mangos. Otherwise, in the future, you will get confused by looking this code. In the response at the place of command, we add reply, and here we pass command, dot replies, square bracket, command, dot replies, dot length minus one. By this, we get the latest reply which we just add. Save the changes, and let's taste this API back to Postman, and here we duplicate this comment API change its name to adding a new reply. Now in endpoint, after commans we need to add comment ID. Let's copy the comment ID from the previous API and paste it in our API. After comment ID, we add slash replies. Now let's also change the reply text to thank you so much and send the request. See here we get the success message and also we get the last reply. So you can see how simple it is. 181. Exercise - Removing Specific Comment: Now it's time for little exercise. In this exercise, you have to create a new API for deleting the specific command from the post. So our APIURL will look like this slash API slash post post ID, slash commands, slash command ID, and you have to remove this command with this command ID. Also, make sure only the user who uploaded that post or the user who add that command can remove that command. Not all users can remove commands. It is really simple. I know you can do that, give it a try and then watch the solution. I hope you solve this exercise, and even if you stuck somewhere, don't worry, at least you try. That's matter the most. Now let's quickly see the solution for this exercise. Here, we simply duplicate this last API because it is very similar. First of all, we change the method to delete. Also, from the endpoint, we remove slash replies because we don't need it. Now in the function, first, we don't need this text. Also, we don't need this condition, and also we don't need this new reply variable. In the fine one and update method, we need to add our condition. So first one is the underscore ID to post ID, and now for finding the command, and we need to make sure current login user should be the author of the post, or he should be the author of the command. So here we use dollar or operator, and it is an array of condition. Object, object. Here, our first condition should write or second condition should write. First of all, we check current user is the author of the post or not. Here we add user column, user ID, and for second condition, in another object, we pass codes, comms dot underscore ID to comment ID, codes, commenst user two user ID. What we want to do if any of these two condition is true. We want to pull that command from the commands array. Here at the place of push, we use pull operator and from which field we want to pull. Yes, we want to pull from commands, and here we pass the condition, which item we want to pull. So in object, we pass as good ID to comment ID. Now we don't need this comment variable, and in the response, we simply return message, comment, deleted successfully. And also, we return commands to post dot Commans and that's it. Here what I think we should check post is found or not. Otherwise, we directly get this message without doing any deletion. So before this response, we add, I post is not available, then we return response with status code 403, and in the Jason, we pass message to unauthorized or post comment not found. Will useful. Save the changes, and let's test this implementation. Back to Postman. And here, let's duplicate this reply API test, change the name to deleting a specific command, method, to delete. And in the endpoint, we just need to remove these replies and send the request. C commentate it successfully, and if we again send the same request, see, here we get not found error, so it is working. As you can see, creating API is not hard. If the logic is clear to you, then you can create any kind of API. Now there are many more APIs for post and comments. We are not creating all of them because as you can see, it is repetitive and if I show you all APIs one by one, then it will also bore you. You can define APIs according to your project needs. It's totally up to you. 182. Error Handling: Now currently in our project, we didn't add error handling. So I open here our previous project, Card Wish, and from the index dot JS file, we simply copy this logger variable and also the both error handlers and in our inkifiPject in Config folder, we create a new file called logger dot js and pise that code here. Now, in this file, we need this Winston object. So in terminal, we write NPM, install Winston, at the rate 3.17 0.0, and also we need Winston MongoDB, at the rate 6.0 0.0, and eight Enter. Good. Now at the top, cost, Winston is equal to require Winston. And also, we need to add require Winston Mongo DB for logging in the database. Now in our logger, we need to change this database string to process dot nw dot dB. And at the very end, we simply module dot exports is equal to logger. We can use this logger in any of our files. So in the index dogs file at the top, we add Const logger is equal to require. We go to Config folder and in that logger. Now, from the previous project, we also copy this cache method of Mongoose connect and simply replace it with our cache method. So from the Cardwih project, we copy this custom error middleware for handling errors in API request and paste it in our Linky fi project after all our routes. Also, here we can console dot log error for simplicity. Now you might ask, we don't need to add those functions for handling ungod exceptions and unhandlePmise rejections. Yes, here, we don't need to add them in our index dogs file because when we import logger from loggers file, these two methods will automatically execute because they are set up globally in this file. And that's why we get here clean code. So you can see how simple it is. Also, I always add this logger file in my Github repository. So whenever I need this error handling code, I can get it directly. But for to understand what is inside the code. If you know that, then you can use any code and make it yours. That's it for this section. In the next section, we will learn very interesting real time features. See you in the next section. 183. Section 15 Introduction: Welcome to the 15th section of the ultimate no JS course. In this section, we are going to learn about real time communication from our back end to front end and also front end to back end. This is going to be fun because we will also taste our implementation with the front end like this. Imagine these are two users from different computers and they are chatting with each other on our inkifi application. See how smoothly it works. Our both users are getting real time messages, and also when one user is typing message, another user getting the typing indicator, which makes user experience one to chat. Also, we will implement group chat, and by that, more than one user can chat in groups. So we will implement these features in our back end and taste it with the front end. Also, one thing I want to clear is here we are not going to create front end from scratch. Is just for tasting, so you can understand more about these real time features. I'm very excited for this section and hope you are too. So let's get started. 184. Creating Chat - Message Model: For creating the Jet API, first, we need to create Jet collection or model, whatever you want to call it. So here in our models folder, we create a new file called chats dot js. Now, from the previous user model, we copy whole code and paste it here. Good. Now, first, we change the variable name to chat schema. Also, let's remove everything from the schema object and also change this user to chat and done. Now, let's define the chat schema. But before that, let me clear what is chat here. Hat is like a room in which two or more users can communicate with each other. In simple words on Instagram, did you see on the left side, we get all chats shorted by the latest message. Those fills are chat. It can be groups or it can be individual chats. What we need for these chats. Currently, we are just implementing one to one chat, so don't worry about group chat features. Just think about one to one. So for individual chat, we can create center field, and also we can create receiver field. And for both, we add type to Mongos dot schema dot types, dot Object ID, and ref to user. So suppose user A sends the message to user B. We add user A as sender and user B to receiver. Now here is one big problem. Suppose now user B is sending message to user A. Then sender will be user B and receiver will be user A. This will create a new chat document, and these both users will not get the same chat for talking to each other. Now what is the solution here? It is really simple. So at the place of defining sender and receiver both separately, we can add single field for them. Like here, we had participants, which is the array and in that we will store the user ID of participants. Type to Mongos dot schema dot types, dot object ID, and ref to user. If user A sends message to user B, then we have user A and user B, both IDs in the participants array, and if user B sends message to user A, then also both IDs are available in the participants. By this way, we will get single chat for user A sends message to user B, or user B sends message to user A. This participants fill is used to fetch jets for specific user. Now, after participants, we want date and time. For that, we can simply enable timestamps to true, and that's it. Now you might ask what about messages? For messages, we will create another model. So copy this schema, and in the models folder, we create a new file called messages dot js and paste here that's schema. Now, first, we change the chat schema to message schema and chat model to message. Good. Now let's define schema for single message. So for message, first, we need its chat ID. So type to Mongos dot schema dot types dot Object ID, and reference to chat collection, which we just define. Now after that, we add sender who sent this message and it's type to Object ID and reference to user. So we can simply cut it from the participants and paste it for sender. Now we don't need this participants. After that, we have content type to string, and required to true. This is the message content or message text which users wants to send. Now after content, what we add, yes, we need status of that message. Type to string um to array, and here we define the set of values like send, delivered, and read. And by default, we set status to send. In the future, we will update status when our message delivered or read by other users, and that's it. Also, for messages, we add timestamps to true forgetting the date and time. Now you might ask why we don't add these messages in the chat model. We can do messages to array and define all messages with its related chat. Yes, we can do that, but one reason why we don't add messages in the chat model because in the messages model, we are going to perform add, update, and delete many times. We add messages in the chat model, then we need to deal with really deep nested data, which can confuse us. And also, if we add messages array in the chat model, then when we open chat, we have to fetch all messages from the back end, and that is a lot more data in single request. So by separating the messages, we can only send last ten or 15 messages, and then if user wants to see older chat messages, only then we will fetch other messages using Pagination technique. So that's why we separate messages from the chat model. Here in the chat model, we can also add one more fill. Last message, which is type to Mongos dot schema dot types dot ObjectID and ref to our message model. By this, we can display the last message with chat and we don't need to find it from the messages collection. Now in the next lesson, we will create API for getting the list of jet for login user. 185. Getting Chats For User: Let's create API for getting the list of jet for logged in user. Here in the routes folder, we create a new file called jets dot js. Now, first, we create Router, so Cs Router is equal to require Express. This expression will return Express Object, and here we simply get dot Router. This is the single line code for these two lines which we are using till now. At the end, we simply export this with module exports is equal to Router. Now what we will do, we also add these routes in the index dogs file, press Control plus P and go to index dogs file. Here we add cost jet routes is equal to require, we go to routes folder and inside it jets at the very bottom, app dot U here we add prefix API slash jets at the second parameter, we add jet routes and save this. Now we can define our APIs. First, we want to find out the list of jets for current log in user, router dot get endpoint to forward slash, and here we need Os Middleware because only log in users can see chats or do chat. At the end, we add Asyn callback function with request and response. Now inside this callback function, first, we get cost user ID is equal to request dot userid dot underscore ID. Next, we can find chat. Cost chats is equal to await chat. See, auto input works dot Find and here we pass our condition in Object participants to user ID. Here we can also use Mongo Di Be operators, but this will work as well. If it doesn't work, then we will change it. What is the matter? Now on the front end, we want to show something like this. First of all, user who receive or send messages. Also the last message, who send the last message, and on which time they send. Here we need to populate the user data of participants. Dot populate. In the first argument, we pass the fill name, which is the participants, and second argument is fills name, let's say, underscore ID and user name. Now also we need the information about the last messages. Again, populate what we write first. Write, last message, fill name, and then second, which fills we need from the last message. First, we need sender who sent this message. Next content, the text of the message, and next, it's created at. Here, if you are confused about Phil's name, then you can also watch Schema. Now here, little bit challenge for us. As we can see, we are getting sender of this last message, but it is also ID, not the user name. We need username of that sender. So here we can do like this. After this populate method, we add another populate method. First, we add last message dot sender and second argument, we add fill name, which is username. Now I think this looks a little bit confusing. So there are another way to write nested populate method. Let me show you. Till now in populate method, we pass two arguments. On first argument, we pass the field name which we want to populate and at the second, we pass the properties which we want to get from the relation. This is the first way. For nested populatet method, we can pass here populate method. Now instead of pass here arguments, we can pass object. First, in this object, we pass path property. This path is a field name which we want to populate, which is last message. And another property is select. Here, we select which data we want to get from the relation. Let's say center content and created at. Now here we want to again populate the sender data. After select, we pass another property which is populate and here we pass object with same two properties path and select. Path to what we add here, write sender. We don't need to write here last message dot Sender because we are already in the last message populate method, and here we pass select to user name. Here, if you want to go more deep, then we can also pass another populate property, for now we don't need it, so let's remove this. Now here, these two populate methods and this single nested populate method both works the same. I like this nested approach because it is clear and not confusing. If you like first one, then go for it. Don't worry, it's completely up to you. Now after populate, we want to show jets in reverse order of the last message. But here, how can we sort jets? It is really simple. See when someone sends message, as we know, we will update that jet, last message property, and when we update that property, our jets updated at property gets updated. So we can short by that updated at property. So dot short, and in object, we pass updated at value to minus one, and at the end, we return response dot json, Object with chats to these chats, and that's it. Currently, we get the chat list for login user. Now, next, when user open one specific chat, then we need to show them messages of that chat. In the next lesson, we will create API for that. 186. Getting Messages of Specific Chat: Let's get messages of one specific chat. So outer dot GT. First, we need the ID of the chat, so slash column, chat ID, slash messages. Also, we need here or middleware and at last is in callback function with request and response. Now inside this callback, we get cost chat ID is equal to, and we destructure request dot PAMs. After that, cost messages is equal to await message dot find. Simply here we pass Object chat ID to chat ID. Let me check it is chat or chat ID. Yes, it is chat ID. When I was learning not Jazz, this happens to me. I write wrong fill name in the query and spend almost a day finding error, and at last, I check the fill name. So make sure it not happens to you. Now here we want to populate this data. So dart populate. And here we want to populate sender, and what do you want to get underscore ID, and user name. Now, after that, we want to get messages in reverse order because that's how we display messages on the front end. So sort here in object, we pass created at to yes, minus one. Now, this query will return all messages of this chat ID. But in real world, we only need last ten to 20 messages because nobody will see messages from the start. If someone wants to see previous messages, then we can fetch it later as pagination. So for pagination, we write here, let Ci brackets, page comma limit, is equal to destructure here request dot query. Also, we pass here that default value if front end will not pass this data. So page to one and limit to let's say ten. After that, we need to convert them in integer. So page is equal to pass integer and pass here page. Duplicate this line with sift plus Alt plus down arrow or Sift plus Option plus down arrow. And here we change this page to limit, and also here limit. In our query, we simply add Skip method, and inside it, page minus one into limit, and we also add limit method and pass here limit. And also, at the end, we add len method. We create a lot of API with pagination, right? Now we can also add here C has previous messages, is equal to here we pass condition, messages dot length is equal to limit. If it is true, then return true, else, we return false. Now at the end, we simply return response dot JsunObject messages to messages, has previous messages, to a previous messages, page to page, and limit to limit. And that's it. For now, we don't have chats and messages, so we will taste these APIs after we create chat and messages. In the next lesson, we are going to create sending message EPI. 187. API for Sending Messages: Now let's create API for sending messages. So here we add router dot post for endpoint, we add for our slash column jet ID, in which jet we want to send message, slash message or messages, whatever you want to call it. Also, we add Osmitalware and acing callback function with request and response. First of all, we will get user ID from the request dot user dot underscore ID. As we get cost Calibakets chat ID is equal to request dot PRMs, what else we need? We need content of the message which we get from the body. Cost Calibacket content is equal to request dot body. Now, before doing anything, let's check here condition. If content is not available, then we return response with Stata code 400 and in the JSON method, we return object with message to content, or we can say message, text is st required. Now what we want to do inside this API, we want to simply store message in the database. That's it. Here we can do cost, new message is equal to new message. Here in the object, we pass jet ID to chat ID, sender to what write, user ID, and then we add content to content. After that, we await new message dot c. And at last, we simply return response with Status Code 201, and in Jason, we pass Object, new message to new message. Now before we taste this API, you might ask, we didn't create API for creating chat. Then how can we pass jet ID? Your question is right. We need to create Jet API before we save message. Here we create a new API, router dot post, point to slash Create chat. Here, we need middleware and also in callback function with request and response. First of all, we get Cost user ID is equal to request dot user dot underscore ID. Also we need receiver ID, who is the receiver or another user of this jet. Cost receiver ID is equal to request dot body dot receiver ID. As we are getting this receiver ID from request dot body, it's good practice to validate. So I receiver ID is not available, then we return response with Status Code 400 and in Jason, we return object with message to receiver required. Now before we create a new chat, it's better to find these two users have already existing chat or not. So let chat is equal to await chat dot Fine one. Here in object, we pass participants to object, and in that we add dollar or to array, user ID, comma receiver ID. Now, this query means a jet in whose participants there are these both user ID and receiver ID. Now, what if it is a group jet? Then it might possible there are multiple jets in which these both IDs are available. Here we need to make sure only user ID and receiver ID should be available. For that, we can use here dollar size to two. This is another useful operator of Mongo Dib. I recently learned about it. Now, what if there are really no chat for user and receiver? Simply then to create a new chat. So if chat is not available, then we do chat is equal to New Jet. Here in the object, we add participants to array user ID, comma, receiver ID, and then we can await chat dot c. At the end, we simply return response which status code 201. In JSON, we simply send this chat and that's it. Now we have create Jet API, before creating a new message, we should first check user pass a correct chat ID or not and also is the participant of the chat or not. If we don't check this condition, then anyone can send message to any person or group. Cost chat is equal to await chat dot fine buy ID, and here we pass JatiD. And after that, we check if Jet is not available or jet dot Participants dot includes user ID. If sender is not in the participants, we pass your exclamation marks, and then we return response which status code 403, and in JSON message to access denied. Now we verify jet. Now in the new message, we replace this chat ID to chat dot underscore ID. Now, what else we have to do when we send a new message? Can you guess? Right, we have to update the last message property of the chat. Remember, after we save the message, we write chat dot last message is equal to new message dot underscore ID. And after that, we also await chat dot save. And that's it. Now finally, T is this API. Open Postman and here we create a new folder called chats and inside it, we add new request called create a new chat. Good method to post. I endpoint, we add SGDP, Column double forward slash Local host, Column 3,000 slash API slasheTS slash CretHaT. First of all, we need to pass token in the header. Back to our login API and here for Hari account, good copy this token and in our create chat API in headers, we had authorization to error, pace that token and send the request. See, here we get internal server error is because receiver ID is required. So here in the body, we go to aw. Here, we pass JSNObject and pass here receiver ID to codes, back to Mango Di Becompass and here I copy this other user ID and paste it in the receiver ID. Now send the request. See here we get new jet, copy this jet ID. As Test, send message API. Make sure you save this API with Control plus or Command plus a, and then duplicate this post request. Change the request name to send a new message. Also, I notice in our API, we have to pass chat ID in the request parameter and content in the request body. So we can do something like this. We can change our API and point to only send messages, and here we get chat ID in the request body. Good. Save these and back to Postman. Here, we change our endpoint to slash chats, slash send messages. In header, we already have token, so we just need to pass request body. Here in the object, we pass content to let's say this is the first message. Also we add jet ID and paste that jet ID here. Now send the request. See here we get the new message content to our message, and in the sender, it is our ID. Now it's better that at the place of sender, we can see the ID and user name. By that, it's easy to display new messages on front end. At the very end, we define cost, populate message is equal to await message dot find BydNew message dot underscore ID, dot populate. First, we add sender, and at the second argument, we add underscore ID and use a name. And in the response, we return new message to populate message. Save the changes, and let's send another message. This is the second message, and send the request. See, in the sender, we get ID and user name. So here, our send message API is working well. Lovely. 188. What are Web Sockets: So in the previous lessons, we created APIs for sending the message, and also we define API for getting messages of specific chat. Now imagine this is our front end, and it has open chat page for two users Hurley and Mike. So this is the screen of Hul and this is the screen of Mike. Both are on the chat page in which they both are participants, and they both gets two messages which are history chat. Now imagine here Harley type a new message and click on Send. So on the Send button, we will call API for sending a new message, right? And as we know, this API will save this message in our database. Now the problem is how Mike will get this message because Mike already fetched all messages of this jet and after that, Hurley sends the new message. One was, Mike will send get messages request in every 5 seconds to get new messages. It's like Mike asks the server, is there any new message for me? Server says no. Again, after 5 seconds, Mike asks, is there any new message for me? Again, server says no. Then if server gets new message, then in another 5 seconds when Mike again ask for the new message, at that time, server will send him message. Now imagine we have 10,000 or 100,000 users on our website, and all users are sending message request in every 5 seconds, which is really meaningless because we will only get new data when our server will get new data. Otherwise, our requests are just going to server and coming back. This will definitely makes our server slow or even crash sometimes. So here we can't rely on this solution. We need something which automatically tells Mike if he has new message and automatically send on the mice screen. And to solve this issue, we have web socket. So what is web sockets? Web socket is a way for our website front end and our server backend to communicate with each other in real time. It is like two way conversation. In simple words, web sockets will help us to build real time conversation. Of a web socket connection is like a phone call between your browser and the server. Once the call is made, browser can talk to the server and server can also talk back anytime. Now you might ask, what is the difference between APIs and web sockets. Imagine this is our front end and this is our server. Now suppose on the front end we want to get some data, so we send an API request from the front end to our server. Server will process that request and send response to our front end here our API connection is closed. For example, from front end, Harley sends a message to our server using post API. Now our server will store that data in the database and then return the new message to the front end. Here, our connection is closed. This is the way of connection using SGDP APIs. Now let's see how web socket works. Here we have front end, and this is our server. Now, first of all, here we create connection using web socket. By this connection, our client can send the new messet data to the server without any API call. Same as server can also returns new messet data. After server did a new message data, still this connection stays there. It will not close until we close our website or we manually close it with the code. Let me explain you with the real world example. Here is Harley, here is Mike, and here is our server. Suppose Harley and Mike both builds connection with our server using web sockets. Now if Halley sends new message to server, server will store that message in the database, and then it will send that message to the mic without Mike send API request. Now, if Mike send message to the server, server will also store that message in the database, and then it will send that new message to Harley. Now if our server will get another message for Mike from different user, then also Mike will get that message, but this will only happen if Mike build connection with server using web socket. If Harley is connected with server, but Mike is not connected to server using web socket, then the new message will store in the database, but it will not reach to the mic. That's how web socket works. Web sockets are used for building real time communication between front end and back end. Don't worry, it is really simple. Understand all this when we apply web sockets in our back end and taste it with the front end. 189. Connection of Socket: Now in the previous lesson, we see that if we want to send and receive real time data, then we have to connect with web socket for dealing with web socket, we will use the most popular library socket dot IO. This library is used by many popular platforms, so we can definitely use it. Open up terminal, and here we write NPM install socket dot IO at the rate 4.8 0.1. It Enter. Good, minimize this terminal, and let's add socket in our backend application. In the index dot JS file, we input cost Coli Brackets, server is equal to require socket dot IO. And at the bottom, we can add cost AO is equal to new server. Now in this server, we have to pass our SGDP server. Without SGDP server, the socket will not get connection request. For that, we need to create SDDP server. Cost SDDP is equal to require SDP. This is the built in SGDP module at the bottom, we add Const server is equal to SDP dot Create Server. Now we can pass this server in our socket. Good. Now here is one question on which board the socket server will listen. Because here for Express app, we define port 3,000 and at the end, we listen with that port. In our current implementation, if we add socket dot Listen to 5,000, then our APIs will run on port 3,000 and our socket will run on port 5,000. This is not we want. We want our APIs and socket both works on the same board. So for that, here in the create server, we have to pass this Express app. By this, this SGTP module will create server with this express app, and that same server we are using for initializing socket. Also at the bottom, we need to change this app dot Listen with server dot Lisen. Otherwise, this will not work properly. Save these changes, and let's restart our application to make sure it is running properly or not. See here we get server is running on B 3,000, and we also get Mongo Db connected. That means it is working properly. So to quick recap for initializing socket in our back end, we need to first create server and pass Express app insideE then we can use this server to create socket server, and at the end, we have to also server dot LISN to this port. So here we successfully initialize socket in our application. Now from the front end, anyone can connect to this socket. But what do we want to do when someone connect to the socket? We need to add that logic. It is really simple. Here, after these app routes, we add IO which is the socket instance dot on, and at the first argument, we pass connection, and at the second argument, here we pass callback function and what we do when someone connects to our socket. For now, we simply console dot log. User connected. Whenever from the front end, someone connects to our socket, then this callback function will run. Now, how can we taste this implementation? For tasting that, I created one dummy, simple SGML, and JavaScript application. Don't worry. If you don't know anything about front end, I will explain you that. Also if you don't want to taste it, then you can see this tasting. Will also help you to understand the workflow of the socket. In the resources folder, we have Project three folder, and in it, we have LinkFi testing app, copy that folder and move to our projects folder. Here we paste that folder. Now open this folder in Vas code. Good. Here, we first use this simple chat folder. The reason why I use here front end app because with real front end, learning socket will be fun, and also it will clear full workflow of socket. Don't worry, you don't need to write any code here. Just do as I do. So to run this front end, track this simple chat dot GML file in the browser and open it in the new tab. See, here we get this type of interface. Now back to the front end vis code and open this simple chat dots file. At the top, you can see write socket is equal to AO and inside, we pass our backend Link, which is Local host column 3,000. This expression means we want to connect with socket, which is initialized on this pot. Also, you might ask how we are getting this Ao method. We are getting this Ao method because I added socket with Dan Link. See, here it is, and because of that, we are getting here Aomthod. Save this page and back to our front end. Let's check our Console, so right click on the page and go to Inspec. See here we get this course error for local host column 3,000 slash socket. Now you might ask, we already enable course in this express app, why we are still getting this course error? The reason is we only configure course for our express app, but we have to also configure course for our socket server. It is really simple. Here in the server method, at the second argument, we can pass the options for the socket server. I object, we pass course here also object, first property origin to star, which means any port is allowed. Also, if we want to pass only our front end, then here we can pass that URL. But for now, we stay with star. You can copy or port from the front end browser. Now after origin, we can pass methods, which is array and we pass here, Get and post. This method of sun specify which SGDP methods are allowed during the web socket ndsaC. Now you might ask what is websocket Hensak. When a client connects to a socket or di server, then it start with SDP request. The handshake. If it is successful, then it will upgrade to a web socket connection. During this handshake, the server checks if the incoming SDDP method is allowed or not. It's important to add these methods because with that, our connection will establish. If we don't specify the correct methods, then browser might block the connection due to course error. Save this and let's refresh our front end. See, here we don't get any error, and if we check our back end in the terminal, we get Console message a user connected. And also we refresh our application one more time. Then in our back end, see, here we again get a user is connected, which means our front end user is connected successfully with our back end using socket. So to quick recap, after initializing socket, in our back end, we add ao dot on connection, and at the second argument, we pass callback function. So whenever a new user connect with our socket, then this callback function will run. And also inside this callback function, we will write all our logic for socket. That's how we initialize and handle the connection of socket. 190. Socket Emit and on methods: You might think writing a socket related code is difficult. It has many methods and functions. How can we learn them? If you have these types of equations, then don't worry. For the first time, I also think socket is very difficult. But when I actually apply it in my project, it is really simple. Socket has mainly two methods, socket dot d and socket dot on. 90% time, we will use these two methods, and trust me, they are really simple. So as we know, socket is used for real time conversation between front end and back end. Basically, it means anytime our server or back end can send and receive data from the front end without any API calls, and it works in reverse as well. Front end can also send and receive data from the back end. Suppose from our front end, Harley wants to send one message to back end like this is the new message. Now the thing is, how can we send data from the front end? So for that, we use socket dot E send message. This is the event name, and at the second argument, we can add our data. In plain English, emit means send. So we are telling our socket, emit the data, or in simple words, send the data. By this, we send message from the front end, but in the back end, we need to also write the logic for handling that event. And for that, we use socket dot on send message. This is the same event name which we send from the front end. And at the second parameter, we will pass callback function, which will run when we get send message event. So we will write all our logic in this callback function. Whether we want to store message in the database or we want to directly send them to other users. In simple words, just remember when we want to send data from front end to back end or back end to front end, we will use socket dot method with event name, and when we want to receive data from the back end or from the front end, then we use socket dot on, and here we write the same event name and callback function. Let's implement this in our application. So on front end dab first, here I added submit event for our form in which we have message input and submit button. And here we get input message and use a name filled in these two variables. So everything is set. We have to send message using socket. So here, which socket method we use for sending the message. Right, we will use socket dot m. At the first argument, we write the event name, let's say, send message. And at the second argument, we can pass data we want to send with this event. Let's say we pass here object with sender to object under square ID to let's say 123 and use a name to username dot value. And another property content to input dot value, which is our message text. Also, we send created at to new date, and also we pass status to send. And that's it. Here, we added fills as we define in the database. Here, by this code, we send the message data when we submit a form. Now, let's see if we are getting this data in our backend or not. So tell me which socket method we will use for getting the event data. Right, we use socket dot on. You learn pretty fast, lovely. In our back end in the ao dot on, we at socket dot on. At the first argument, what do we pass? Right, we pass event name which we want to handle, which is send message. Make sure you write the same name as we pass from the front end. Otherwise, it will not work, and also it is case sensitive. Now at the second argument, we pass callback function, which will run when someone from the front end send this send message event. In the parameter of this function, we get the data, and for now, we simply consoled log new message from front end, and we adhere this data. This data is the message object which we pass from the front end. Now you might ask, how can we get socket in this o dot on callback? Simply we get here from the parameter. Using this socket, we can add emit and on methods. Save these changes, and let's send message from the front end. Refresh the page right here, user name and right here, message, first message, and click Onsent. Here, nothing happens. And if we check our back end, check our terminal. See here we get user connected, and then we get that message object, which means we successfully get the message from the front end. That's so simple to send and get data using socket. Just we have to remember socket dot and socket dot on method. Now here we get the message from the front end. Next, what we want to do with that message. Obviously, we want to store that message in the database and then return that message to front end our front end can display that message on the screen. For now, don't worry about database logic, we will implement it later. For now, we just want to send this message to front end. Tell me which method we will use for sending the data from back end to front end. Yes, we use socket dot, and at the first argument, we pass event. Get message. You can give it any name. It doesn't matter. Now what do we want to send with this event? Want to send the same data. In real world, we will send new message object which we store in the database. Now save this file, and in the front end, we need to handle this G message event, and you already know which method we have to use for handling the event or getting the event. Right, we will write here socket dot on. First, we pass the event name, Get message, and at the second argument, we pass callback function, and in that callback, at the parameter, we get that data. What do we want to do with this message? Simply, we want to show that message on the browser. So for display the message, I created this display message function. Simply call this and pass the data in it. This function will create message and display it on our browser. Also, here you can see that logic if you want to. Save this, and let's taste this implementation. Make sure you refresh the page after doing any changes in the front end code. Otherwise, you will not get these updates. Now we use a name to Hurley and message to first message and send the message. See, here we get the message on the front end within a second or lays in second. So to quick recap, socket has mainly two methods, socket dot m and socket dot on. Socket dot is used to send or emit the data. And with socket dot on, we can handle that sent event or we can see the event. If you understand these two methods, then congratulation. You 90% socket is done. It is that simple. 191. Getting messages for both users: In the current implementation, we taste it with one user. Now let's taste it with two users at the same time like Haley and Mike are talking with each other. So open another private tab of the browser, or you can also use another browser and open the same S DML file. Now suppose first screen is Halley spec and second screen is Mike spec. They are chatting with each other. So here Halley sends message, and here he get this message, but Mike is not getting the message. How here from the back end, we are sending message with socket, how it is working for Halley and not working for Mike. The reason is here from the back end, we use socket dot m. This method will send event to only that user who emit the send message event, and that's why Halley is getting this message, but Mike is not getting. Now, what is the solution here? Because we want our message, we'll send to other users as well. Simply at the place of socket dot, we will use this ao dot method. Using ao dot, we can send message to all users who are connected with socket. Save this file and let's taste this implementation. Refresh both pages. Good. Also, here we write username for both users and from the Hal we write message and send it. See, now Mike also get this message. And if we send message from Mike, see, He also gets it. And it is how real time chatting works. By using socket dot from the back end, we can only send event to users who emit that event. And if we use ao dot, then our socket will send that event to all users who are connected using socket. 192. Logic of Joining Chat Room: In the previous lesson, we are getting messages instantly in both users. What if we add another window and see what will happen? So let's add another private window and open same HTML file. Now write here, user name and from the first window, we send message. See here for both user, we get the message. And if any other user send message, then also other users are getting that message, which means our socket is sending the message to all users who are connected to the socket. It's like you host one big party. Here, people are chatting everywhere without rooms, and because of that, all conversation would mix up. It's like user A talking to user B, but user C hears everything, so there would be no private conversation. How funny it is everyone is suting across the whole house instead of talking gently in a room. Here we also have the same situation. Our current implementation is sending messages to all users. So what is the solution here? We need to implement rooms. So rooms in socket can solve this issue by allowing us to group users together. Each group or room is private space where only members of that room can send and receive message. In simple words, room in socket are virtual spaces where users can join and live. In that you can broadcast message to everyone in a room without disturbing others. Suppose Halley and Mike's wants to chat with each other. When Halley opens a chat, Halley join with one room which has a unique name like chat HM Halley, and Mike. Now Mike open jet page to talk with Halley. Mike also joined the same room called JathM. Now both users are connected in the same room. So if Halley send message in that room, then only Mike will get this message, not the third person. I Hi close the tab, then Halley lost the connection with the socket and when socket gets disconnect, then socket dot IO automatically removes Halley from Room jet hm. By this implementation, our jets will not get public and also this works in group chat as well. Suppose user A, user B, and user C are group members, and they all are connected to specific room chat ABC. Now anyone of them is sending message. Other two will get this message because they are connected in the same room. You will understand this properly when we implement and taste this feature, and we will do that in the next lesson. 193. Implementing Joining a Chat Room: Now let's implement room feature in our inkifi app. But before that, let me quickly recap the workflow. So when user opens a chat, they join the room with its chat ID. Only users in the same room can send and receive the messages. And at last, when the user leaves or close that chat, then we remove them from the room. So first of all, when user opens a chat, then from the front end, one event should trigger call join room with chat ID. After that, from the back end, we add that user in that room, and when someone sends message, we will send that message to only users who are joined that room. Here in our back end, we handle another event, socket dot on, and which event we want to handle yes, it is join room. Now here we get data, or we can say from the front end, we will send the chat ID, arrow function, and now to join Room, we simply write socket dot join, and here we pass name of the room, which is our chat ID, and to make sure we also console dot log in backticks, user dollar Cali Brackets, socket dot ID, which is the current user unique ID provided by socket. Join Room dollar CL brackets chat ID. Now in the send message, we want to send message to only those users who currently in that room. So we comment out this previous EIT method, so you can look at it later. And here we write ao dot MIG message, and pass here data. Now to send this event to only separate room, here we add ao dot two, and inside it, we need to pass that room name which we set to chat ID. Now the question is, how can we get the chat ID? Right, we can pass the chat ID from the front end. So data chat ID, and that's it. We join user in the room, and then send get message event only to that room. Now to test this implementation, we need to use another SDML file. So in the testing folder, you will get another folder called Romjat and inside it, you will get the file called Rojatt SGML. Also, in its JS file, first, we connect user with socket, and then we are asking for room name in prompt. After we get the room name, we send this join room event. This will help us to join a room, and then rest of the front end code is the same as before. Just in the send message event, we also send jet ID because we need it in the send message. Now let's run this file. Dig this file and open it in your browser. First of all, it will ask for room name. Here, for tasting, we are passing any random jet ID. Let's say chat underscore one, two, three. Okay. As we write use a name. Without it, we might get error. Write use a name, and if in our back end, we open Console see here we can see user connected, and then user socket ID, join room, and here we get our room name, chat, underscore, one, two, three. Great. Now let's open another tab and do the same. Write here room name, chat, underscore one, two, three, because we want to join the same room. Now here we write user name. And then write message and send it. See, for both users, we are getting this message, so it is working pretty fine. Now, let's open another window and join a different room. Let's chat, underscore 45, six. Good. Now, if we send message from this user, these two users will not get this message. And if any of these two users are sending the same message, then this third user is not getting this message. So this is working as well. So that's how simple it is to join room and send message to those rooms. As I previously told you, socket is very simple. Just you need to understand the logic. 194. Exercise - Typing Indicator: Now it is time for little socket exercise. In this exercise, you have to implement show typing indicator when someone is typing the message. The logic is when users start typing in the input, we trigger one socket event typing. And from the back end, we will send data who is typing and in which room he or she typing. Now after implementing that as a bonus, when our user don't type for 2 seconds, then we will trigger another event called Stop typing, which will simply remove typing indicator from the front end. Don't worry, if you don't know about front end code, just write code for backend, handle the event and send that user is typing or any message. In the front end also, I added code, which will work when we write something in the input box. And also I added commands where you have to emit the events and also the code which you have to write when you handle those events. The goal of this exercise is you think in event terms. So try to implement it and then what's the solution. Now, let's see the solution of this exercise. So first of all, in our back end, we have to handle event, let's say typing. So socket dot on typing. And from the front end, we will send object with jet ID and user name. So we can destructure it here and get jet ID, and also we get user name, arrow function. And here we send this message to other users who are in the same room. So o dot two here we pass the chat ID, and after that, dot, show typing. And here we pass message in BTI dollar user name is typing. And that's it. After that, we also need to handle event, stop typing, so socket dot on, stop typing. And here we also get object with chat ID and user name. And in the error function, we simply Iot to chatd dot m, Hide typing. Here we pass the user name who stop typing, and that's it. We don't need any other thing in the back end. In this exercise, if you confuse about front end, then don't worry about that. I just added front end for tasting. You can also skip that tasting part as soon as you know how to write socket logic and event. Now, let's quickly see this tasting part. As I told you in the previous lesson, here at the bottom, I added this code, which will run when we write something in this input box. Here, if input value is not empty, only then we do socket dot m and which event we emit, we will send typing event, and at the second position, we add object with chat ID to chat ID, and then we also send username to user value. In this typing time out, which will run after every 2 seconds when we write anything in the input box when for two second user didn't write anything, then we send another event called stop typing. Here we duplicate this emit method and pass it here and change this event to stop typing. Outside of this event listener, we need to handle two events which we emit from the back end. Socket dot on, show typing. Here, we pass Callback function, and here we get message, user is typing in this arrow function, our front end will write their logic. For now, we simply add here this logic which I added at the bottom with command. Now after that, we add another socket dot on. Stop typing here also callback function. Here we get to use a name if you want to use it. And here we move this second logic for stop typing. Save the changes and take a look, refresh the page, Enter chat, ID, chat, underscore one, two, three, and write use a name, Ali. Now in another window, also we refresh the page. Enter chat, D, chat, underscore one, two, three, and we write use a name to mic. Now let's write something from Mike. See here for Hi, we are getting the typing message. Mike is typing. But here we can see Mike is getting, Mike is typing. This is what we want. We want our back end, only send show typing event to users who are in the chat room, but not for the sender. For that, here at the place of ao dot two, we need to do socket dot two and here socket dt two, firsts typing event. I'll explain you this in just a second, see the changes, and let's test it one more time. Refresh the page, write jet ID, to chat, underscore one, two, three, and write a user name, Harley. And also for Mike, we refresh the page. Enter jet ID, to chat, underscore one, two, three, and write user name, Mike. Now type something see now only Harley is getting Mike is typing, and after 2 seconds, this message is still here. Let me check the event. We handle here stop typing from the front end and which event we are emitting from the back end. Oh, it is hight typing. So on our front end, we change this event to hide typing. Save the changes, and let's test it one more time. Refresh the page. Write chat ID to chat underscore one, two, three, and right here, use a name. So for Mike, we repress the page, Enter chat ID to chat underscore one, two, three, and right here, use a name. Now write message from here and if you stop for 2 seconds, then that message is gone. So this is working fine. Now here is one little thing. See when we send the message, then for little bit, we are getting Mike is typing. We don't want that. So we will also emit stop typing event when we send the message. So copy this socket dot m for Stop typing and paste it at the end of our form submit. Save the inges and let me taste it one more time. Refresh the page, write chat ID and name. Also, we do that same repress, write chat ID and name. Now we write her message and send it. See, now we are not getting that typing. There are four variation of methods in socket ao dot, socket dot I ao dot two room dot M and socket dot two room dot m. Let me explain to you each in simple words. So ao dot show typing. This will send show typing event to all connected users, whether they join a room or not. It will send show typing event to all users who are connected with socket. Next, we have socket dot m, Show typing. This will send Show typing event to only sender. Next, we have ao dot two, room dot show typing. This will send show typing event to all the users who join this room, including the sender. Our case, they are Halley and mic both. That's why previously, we get show typing event for both user. At last, we have socket dot two room dot show typing. This will send show typing event to all the users who join this room except the sender. I Hal is typing, then Haley will not get this show typing event. This is the basic difference between these methods. We can use them according to our needs. There are no rules about using only this or that. We will use whatever suits the most for our logic. 195. Applying real send message code: Now currently in our application, when user sends message, we simply send that message to all users who are joined in that chat room. But in real world, we also need to save those messages in our database. So even if user left the room, he can see those new messages and also the history of the messages. Let's save our message in the database. First of all, I want to clear one thing. When from the front end, we send message, there must be a chat already created between users. For example, if Hurley wants to send message to mice and if they never did chat with each other, which means chat is not created between them. In that case, when Harley sends the first message, we call separate API which is our create chat API, and when Harley has et ID, then we will emit send message event with the chat ID. We already know this, right? Remember, in the starting of this section, we created send message API. Yes, we need that same logic here in the send message event. So let's copy that code. And in our send message event, we simply paste it here. Now, first of all, we need to make this callback function async. Good. Now here we are getting chat ID and content from the request body. But in socket, we don't have request body, so we have to get chat ID and content from the function parameter. So here we destructure this data and get here chat ID and content. Now, what else we need? Right, we need user ID also, so we also get it in this data. And now we don't need this line. Also, at the bottom, we are sending data in the response. But as we know, in socket, we don't get response, so we can simply remove that and from the socket at the place of data, we send this populate message. A in the o dot two, we only at chat ID at the place of data dot Jet ID. Now let's check also where we use our response. Yes, in the returning error, and also here we use response. At the place of sending error through response, here we can send error message through socket event. But the question is to whom we want to send this error message? Should we send it to all users active in that room? No, we want to send this error message to only sender and tell me which socket method we use to only send event to current user. Right, we use socket dot m. Let's send event called error in send message, and we simply send error message access denied. Now here, our bottom code will still run. So to stop running it, we can simply add here, return. Here, we also emit the same error event engine this message to this message. Content message text is master required, and after that, we simply add return, which will exit our code from running this rest of the code. Also, let's remove this code. Now our front end can handle this error event however they want to, whether they show Alert, or they show toast notifications. So here we need to import this chat and message models. At the top, before these routes, we add cost, chat is equal to require period models, slash chats and another cost message is equal to require period models, slash messages, and done. Save the changes, and let's taste this implementation. In the front end, roomchat dots file, we can check in send message we are sending the data or not. Yes, first of all, here at the place of sender, we need to send user ID. For now, we add here username dot value. So in our username input, we have to pass user ID. After that, content to input value. Here, we don't need this created at and status because it will generate automatically by mangoes, and that's it. Save this, and let's rephrase the page. Here, we need jet ID, so we copy the jet ID from the Mongo D we come pass and paste it here. Now we have to write here user ID at the place of user name because in event, we set user ID as this username dot Value. We copy one user ID from the Mongo Divi Compass users collection and paste it here as sender. Now write a message. Let's say socket is easy. See, we get the message and if we check our database, and at the bottom, this new message is also stood, our send message event is working properly. 196. Authenticate user in Socket: Now currently in our implementation, we are getting current user ID from the front end. But in real world, we can't get user ID directly from the front end. Obviously, for security reasons because anyone can take any user ID and send the message. So we need to make it a little more secure. And for that, we will use socket middleware. It is the same concept as we apply middleware in our APIs. As our orth middleware run before every request callback same as the socket middleware will run before our client connect to the socket. Let me show you practically. Here before this ao dot on method, we define our socket middleware using ao dot U. Now in this method, we pass callback function, which will run before our user connects to the socket. For now, we simply add here console dot log, running socket middleware. Save the chanes and let's refresh our front end. Here chat, ID, chat underscore one, two, three. Now, if we check our back end terminal, see, here we first get running socket middleware. But what is this? We don't get a user connected. So here in our socket middleware, our code is stopping here. We need to move it in the next function, same as we did in our Express or middleware. In this callback function, at the first position, we get socket object, which is used to get information about that socket. And at the second parameter, we get next, which works the same as next function in express middleware. Now, after this console, we simply call this next function. Save the changes and repress the page. Enter here jet ID, and now in our terminal, C, first we get running socket middleware, and then we get user connected. By this, it is clear the socket middleware is running before our client connect to the socket. Now in this socket middleware, we can do authentication of user, and how can we do that? We did it before in our auth middleware. Right. For authentication, we use JWT. So in this middleware, we check, user pass the JWT token. It is valid or not. If it is valid, only then user can connect to the socket. And if token is not valid, then we will not allow user because for jet, we need logged in user. Now you might ask, how can we get token in this middleware function? So here we will use the socket object. So Const token is equal to socket dot Hensig. Here we get data which we pass with our socket connection. Our planning is to get data in object OT and inside it, we pass token. Here we write socket dot hensgtth dot token. After this, we simply pass here condition. If token is not available, then what do we do? We simply reject the connection. For rejecting the connection, we return here next function, and inside it, we have to pass new error. Here, we pass error message to authentication error, token required. Now, what if user pass token? Simply, we verify that token, and for that, we need JWT. So at the top, cost, JWT is equal to required JSON web token. Good. Now in the database, we add JWT dot verify. At the first argument, we pass token, and at the second argument, we pass our secret key process dot Env dot JWT underscore key. Let me double check this variable name. Yes, it is JWT key. Now, if this token verifies successfully, then here we get to user data, which we pass with token. We store it in variable called user, and then simply we can do socket dot user is equal to this user. Also, I want to let you know the socket object is different for all users. So when our user connect to the socket, our socket will assign them this object, and because of that, it is individual for all users. This socket user has our current logged in users data. So to see that, we simply console dot log, socket user, and adhere socket dot user, and then we have next function. Now, what if this token didn't verify? We need to handle that case as well. So here we add try and cache blog and simply move these four lines in the Try blog. So anything goes wrong in these four lines, our cache method will run. So in cache, what we do right, we simply reject the connection. So let's copy this next function with the error and paste it here. Also, in our current tasting front end, we need to send the socket dot user data from the back end. So here I simply add socket dot user data event, and simply we pass socket dot user. By this event, our front end will get logged in users data. Otherwise, we need to manually enter the user ID for tasting. Now let's this implementation. For that, we need to run our final testing file. Honestly, this is the last testing file. Don't worry. In our front end folder, we get folder called final testing. And here, as we know, we have to run this SDML file. But before that, let's see what I did in the JavaScript file. First of all, I ask for a token in which we have to enter Jason Web token. If we enter token, then only we will connect user to socket. But wait in this connection, what I did, I add here object which we send to the socket and in that object, we pass OT and also token to our token. This object we are getting in our back end in the socket dot hang dot th dot Tgon. Now, if this token is verified, then our connection will successful. And if this token is not verified or expired, then in the socket dot on Connect error, we get the socket middleware error. And also, when we get user data event, I simply set that data in this user variable. Also all code related to socket, we added here in this if condition. Let's see it is working or not. So open this SDML file in the browser close tabs. Now, first of all, it will ask for token. Let's pass here one, two, three, and as we know, this token will not verified by our back end. Let's see what we get. Hit Okay. See here we get authentication error, token required. Open postman and simply open login API and send the request and get the token. Copy this and simply paste it in our SDML file. See, we don't get the error, and if we check our Bend terminal, we get here socket user to our users detail with ID and user name and we also get a user connected, which means our middleware is working pretty fine. Now, we use this socket dot user in our socket event. In the send message event, remove this user ID from the parameter, and at the top, we add cost user ID is equal to socket dot user, and a Score ID. Make sure you check the ID property name and also in the typing event at the place of getting the username from the front end, we can pass here socket dot user, dot user name, and we do the same in the stop typing event, socket dot user, dot user name. Now also, we remove user name parameter for both events. Now, let's again taste this send message. So repress the page and base the token. Now here we need the chat ID, so copy that also from the MongoiVcmpass. And paste it in the chat ID and click on Join Room. Without joining the room, we can't send message. Now, if we send the message from here, let's say this is final tasting first message. See, here we get the new message, and if we check our back end, then it is also getting stored in the database with the proper user data. So to quick recap in our socket, we should not get user data directly from the front end. Will be no secure. So we create this socket middleware and ask JWT token before connecting user to our socket. After that, we verify that token and simply set the token data in the socket dot user. So here we can use this socket dot user in our whole socket logic. Also, as we know, the socket dot user is individual for all socket users. So that's how we apply and secure our socket using JSON Web Token. Here, as our previous concepts are clear, it is really easy to understand advanced topics like the socket middleware. And that's why I am explaining socket step by step so you can understand it properly. 197. Marking users as Online and offline: How do you know, in many chat applications, we get user active or online mark. Do you think how they apply that feature? Don't worry in this lesson, we will mark users as online and offline. First of all, what do you think when a user is online? Think about it in the human language. Our user is online when they connect to socket, and when user is offline, write, when user left your application, or we can say they get disconnected to socket simple as that. Here before these IO methods, we declare a new variable cost online users is equal to new map. Now, some of you might ask, what is this map? Map is an advanced verson of our object. It is also collection of the key value pair. Map has more features than object. So as we know, in object, key is spring. In value, we can set it to anything. But in map, we can set anything string, number, bullion, object, array, function, any type can be key. In short, for frequent addition removers, map is generally more efficient than using objects. It is designed to handle key value pairs more efficiently. In this map, whenever user join, we can add that user ID as key and its socket dot ID as value. So here in the io dot on connection, we simply write online users dot set. At the first argument, we pass socket dot user dot score ID, which is the key at the second argument, we pass socket dot ID, which is our value. Now we just need to remove user when their connection will lost, which simply means this user is offline. So at the very bottom, we add socket dot on. Here, we pass disconnect, and then we pass Callback function. Disconnect method will run when users socket connection will last. At that time, this disconnect method will automatically run. Also, when user close the browser tab, then also this disconnect method will run automatically. So we don't need to worry about a a disconnect method from the front end. Here we simply add online users dot delete, socket dot user dot underscore ID, which is the current user user ID. See, in the map, we can directly use set and delete method to add and remove key value pairs. Now let's see it is working or not. So we simply adhere console dot log, online users, and adhere online users. So let's copy this console and paste it when we add user in this map. Now, let's taste this. So p the SDML file in the new tab, paste here your token. And if we check our Bend terminal, see here we can see the online users key to user ID and socket ID as value. And if we close our tab, then here we can see our online user is empty. So it is that's easy. You can send these online users to your front end and show indicators as green dot or something else. 198. Multiple sockets for Single user: Here is one thing in our current implementation. As we know, our application will be used on browser or our backend can be used in apps. If our user connected in one tab, then user ID and socket ID will added in the online users. Now, if he opens a new tab and connect to socket, then in our online users, we get another key as user ID. But here, previous key and current key is same because of that, this socket ID will be replaced by new socket dot ID. Now imagine he close only the second tab. It will also remove that user key value and mark our user as offline. But here he is still online. He is still online in the first tab. So here we need to solve this duplication issue. So what is the solution here? We can add user ID as key, same as before. But at the place of setting socket ID directly, we can add array or set of socket IDs, which means two tabs has two socket IDs. We have both in this array, and if user close only one tab, then we can remove only that particular socket ID from the array. You can see how advanced we are going. Just kidding. Let's implement this in our application. First of all, before this, we add cost user ID is equal to socket dot user dot underscore ID. Now here in online users dot set, first we have user ID, and at the second place as value, we pass New Set. You might ask what is set. Set is the advanced version of arrays. Don't worry. They are really simple. The reason we use here set at the place of array is because we can easily add and remove socket IDs from the socket. This line means we create a new key value pair in online users. Key is user ID, and value is set which is empty. Here we want to create a new key value pair if our user ID is not already available in online users. So here we pass condition. If online users has user ID, if this is false, we pass exclamation Mg. Only then we create a new key value pair. So move this line here. Now after we add new pair, or even if user ID is already available, then what do we want to do? Right, we simply wants to add socket dot ID in the value. So we write online users dot G, what do we want to get? Write userID as key, and for adding a value in set, we use dot add method and pass here socket dot ID. And by this line, we add socket dot ID value in set where the key is user ID, simple as that. So here at the place of socket dot user dot underscore ID, we pass user ID. Now in the disconnect, we want to remove current socket ID. So online users dot gt userid dot Dili, socket dot ID. This will remove socket dot ID from the set where key is user ID. Now, what if our user has no socket ID in the value? In that case, we also wants to remove user ID as pair. By that, we can mark our user offline. So we pass your condition if online users dot GET userid dot size is equal to zero. Then we simply online users dot Dilate userID. So as you can see, we can easily add and remove items from the set. Instead of using array where we have to find index of that item and then remove that item, we can easily add and remove items from the set. Let's see it is working or not. So repress the page, page here, our token. Now in the terminal, we get map, which has one key value, user ID and socket. Now in the browser, we open another tab. Here we open our DML file, and again, let me paste the same token. Good, and let's check the terminal. See here we have one user ID, and it has two values, which is our set of socket IDs. Now let's try to close this second connection. Again, check the terminal. See that last socket ID is removed from here, but our user is still online. Now if we also closed the first tab, check the terminal. See, our user is removed from the map, which means now our user is offline. So that's how simple it is to mark users online and offline. I know this section is little bit long, but you can see how this real time application is working. And if you learn this, then you can create many types of real time applications. Now here, you can take little break, drink some water, stretch your body, or listen some music. Here I am also taking little break and we will meet in the next lesson. 199. Update messages deliverd: Let's see how we can update the message status to delivered. First of all, let's figure out the logic of it so you get the clear understanding when you write the code. So status to delivered means message reached to the recipient device. Now there are two situations. Imagine sender sends the message. First, we store that message in the database with status to send. Now, at that time, if recipient is online, which we will know by our online users variable. So if recipient is online, then we immediately mark that message as delivered. This is the first situation. Now another situation is our recipient is offline, which we will also know by online users variable. So if recipient ID is not available in the online users, it means he or she is offline. So if recipient is offline, initially our message status is on send. Now whenever recipient connect to the socket, at the time, we fetch all the undelivered messages and mark them as delivered. This is the second situation. Let's apply them one by one. Our first situation, our recipient is online. If he or she is online, then we simply mark message as delivered when sender sends the message. In the send message event, here in the new message, we need to check recipient of this chat is online or not. Consors to online users dot, and here we have to pass the recipient ID. But how can we get that? Right, we will get them from the participants, but it is an array with sender ID also. So from that array, we have to filter sender ID. So here, const recipients is equal to at dot participants dot filter. Here, we get each ID arrow function and we simply pass here condition ID dot two string should not equals to user ID. Here we get array with single ID because we have only two users in our participants. That's why here in the He method, we pass recipients square packet, index zero, which is the first element and it is Mongo DibiD, we need to convert it into string. Therefore, we add dot two string. Now what do we want to do if our recipient is online? Simply, we return status to delivered. If this is not true, then in else we return sent. That's it. This is our first situation. Now our second situation is our recipient is offline. So when the recipient opens app and connect with socket, then we fetch all undelivered messages and simply mark them as delivered. Here in socket, we listen another event socket dot on, Mark messages as delivered. We will emit this event from the front end when our user logged in and connected with the socket. Now inside this, we need to do some steps. Make sure you write these steps in the command. Otherwise, you will get confused. First one, we have to find all the chat messages in which our user is available. So cost undelivered messages is equal to await message dot find. Also, we make this call web function async. Good. As we know at the first position, here we pass object with condition. So first, status to send and also the sender should not be the current user. Sender in object, we use dollar N for not equals and pass here user ID. So we don't need all fields from the messages. So we add here select method, and inside it, we pass a score ID, chat ID, and sender. Now, this query will find all the messages whose status is sent and its sender is not our logged in user, but it will not check our logged in user is participant in the chat or not. Here we also need to pass chat ID. So before this query, we need to find all the jets in which our logged in user is available. So Const chat IDs is equal to await chat dot find. Here, we pass Object with participants to user ID. This will give us chat like this. But here we only want chat IDs because that ID we will pass in our update query. So for distracting the only IDs from the data in Mongo Di B, we have another method called distins and in the codes, we pass fill name which we want to distract, which is underscore ID. So previously, without distinct method, we get data like this. Now with disting we get our data like this. So we can simply pass these chat IDs in our fine query. So chat ID two calibracet dollar in to chat IDs. So now, it will find only those messages in which our locked in user is available. Great. Now we need to update only these messages. So here we pass condition I undelivered messages dot length, greater than zero. Only then we want to update messages status. In this calibracket await message dot update many. At first, we pass object for finding those undelivered message. So we pass underscore ID to object. Here, we use dollar in, and as we know here, we have to pass array of message IDs. How can we get that? We get them from undelivered messages, which is the array of IDs. We write undelivered messages dot map. Here, we get each message arrow function, and we simply return message dot underscore ID. By this expression, we get the array of undelivered messages IDs because map method returns an array. Also, we can directly pass undelivered messages here. But for now, I stick with this. If you want to do that separately, then you can also do that. Now what do you want to update? For that, we pass another Cali brackets and pass here dollar set to object, status to delivered. Make sure you write the correct spelling which you write in the message schema. So we successfully update the messages. Now here comes a fun part. What do you think? What should we do after this? So to explain this more clearly, imagine Hale and Mike has one chat. Currently, Mike is offline and Hali sent three messages. As we know, by default, its status will be sent. Here, our recipient is not online. Logic in send message event will not do anything. Status will stay as sent. Now, same as Halley, John also send two messages to Mike. Their status will also set as sent. Now, after some time, Mike comes online and he connect with the socket. At the time we update those three messages from Halley and two messages from the John, which means for total five messages, we will update status as delivered. Now, what should Halley and John will get from the back end? Simply we can send Halley's three messages ID to Halley and John's two messages ID to John and tell them messages whose IDs are these, these messages are updated as delivered. So our front end will update the UI part using those IDs, which means front end can show double check icons. Simple as that. Now here is one thing. Imagine Halley send 100 messages and Mike is offline for one year. And when he comes online, after update should we send all hundred messages IDs to Halley, it may increase the data load. So what I think is instead of passing all messages ID, we can send jet IDs which titers are updated to delivered, and that single chat ID will cover all those messages inside that chat. So we don't need to pass all messages ID. So here, our conclusion is we will create an object where property name is user ID, and as a value, we store array of chat IDs which are updated. The reason we use here array of chat IDs because it will also work for the group chat. For a single user, there can be multiple chat IDs whose messages are update as delivered. Now, after getting this object, we will pick this user ID, find the socket ID from our online users map, and simply emit event message delivered and send those chat IDs. Currently, don't think about how front end will update chats. It can be managed. Here our main focus is to create this object and send event message delivered to each sender. Rest of the work done by front end. Our front end will update all those messages in the chat list and messages list as well or simply reroute the data. Let's implement this part. We will go step by step. First one is we need to create that object who has user ID as property and array of chat IDs as value. Const grouped chat IDs is equal to undelivered messages dot reduce here we have two parameters, AEC, which is the accumulator, accumulator is our final result. As we get message which is the single message object, arrow function, and at the second argument, we can pass the default value of this accumulator. So we pass here empty object. First of all, we will check. Message sender is already available in our SC object or not. I AC square bracket for accessing the key of object and pass here message dot sender. If in accumulator, message dot sender is not available, so we add here exclamation mark. Then inside this, we create a property by its name accumulator, square bracket, message dot sender is equal to empty array. After that, we can simply add that jet ID in this array. Accumulator, square packet, message dot sender, dot push message, dot chat ID. This message JetD is Object ID, so we have to convert it into string. At the end, we simply return accumulator. This ensures accumulator keeps growing with new messages. Now in this code, there is one little problem. If one sender has multiple messages in the jet, then we will duplicate these jet IDs in the array, but we don't want to send duplicate jet IDs in the array. So at the place of this array, we can use set. Set will not add duplicate values. So at the place of this empty array, we add new set, and at the place of using dot push method, we use dot Ed method for set. The group chat IDs will return an object with sender as property and set the chat IDs as value. Now also at the end, we need values in array, so we have to convert set to array. For that, we use here for loop const, sender in group chat IDs. In that loop, we simply group chat IDs, square bracket sender is equal to empty array and inside it spread operator and we simply add group chat IDs square bracket sender. Now we have our object with user ID as property and array of chat IDs as value. Now we have to just emit to the sender and pass jet IDs array as data. Here we again use for loop, const sender ID, grouped jets. The sender ID is the key of our group chat IDs object. Now in this loop, we have to find the sender ID is online or not. So Const sockets is equal to online users dot Get sender ID. If we have sockets, which we already know that can be array and we use sockets dot for each. Here we get individual socket ID, arrow function, and inside it, we simply Ioda two socketd.it message status updated. At the second parameter, we pass data object IDs to group chat IDs, square packet sender ID. This will send all CAT IDs to this sender. So if you want, we can declare it separately. So cost chat IDs is equal to group chat IDs, square bracket, sender ID, and at the bottom, we pass chat IDs to chat IDs and done. Now let's is this implementation. So the changes, open browser. In first window, I log in with Hal's token. And at the second window, I logged in with another account. Generate a new token for another account. And paste it on our website. Now, let's join Room. So copy chat ID from the Mongo Dew compass and paste it and join the room from Hi account. Now I send message. This is testing for first delivery situation and send it. See, here we get delivered. This is our first implementation when our recipient is online. Now, let's test when our recipient is offline. So let's close this second window and again, send the message from Hi this is testing for second delivery situation. See here we don't get message delivered. If we check our database, message collection, refresh the collection, and at last, we get our message status is sent, which means not delivered. Now, when our second user come online, this message status should update and Hardy also gets the chat IDs whose messages are updated. Let's open SDML page in second Window. Log in with second account token, where is this, copy this and add it in token. Now, the moment we hit Okay, S on the first window, we get the notification icon on this tab, and when we move to that window, we get your send messages are delivered. This means our implementation is working well, and also in the console, you will get jet IDs which are updated. Is very interesting part of chat application. Even changing status to scene is not that difficult as this updating status to delivered. If you are confused, then you can see this lesson again, understand the logic and with that, compare logic with your code. By this way, your all doubts will clear. Now in the next lesson, we will implement update messages status as seen. 200. Updating message status to seen: Let's see how can we update the message status to scene. Status seen means our recipient seen that message. So here we also have two situations. Let's understand them with example. Imagine Harley has four unseen messages from Mike. All these four messages status is delivered. Now, the moment Halley opens the chat of Mike at the time we update these four delivered messages status to scene. So we have to fetch delivered messages and update them as seen when our user opens the chat. This is our first situation. Now imagine Harley is already available in the chat or room, and Mike sends a message. At that time, also, we need to mark the new message Setters to scene because Hurley is already available in the chat room. This is our second situation. Let's implement them one by one. So in the first situation, we have to update stats when our user join the room we chat ID. So here we listen one more event, call socket dot on, Mark messages as seen and we pass here callback function. First of all, we will again find all messages which are unseen by our current user. So const unseen messages is equal to await message dot find, and here we pass comparison object first chat ID to chat ID, and we will get chat ID from the front end in this parameter. A let's make this function async. Back to our comparison object, chat ID to chat ID, sender to Cully brackets, dollar NE not equals to user ID, which is the current user ID which we are getting from the socket middleware and As we pass status to delivered. Now here also, we want to get only selected fills, so dot select and ascore ID and sender. Now after this fine query, we adhere condition if unseen messages dot length is greater than zero, only then we run update query. So in this condition, we write await message, dot update, many. At first, we need the same condition object. So copy this object from the find method and paste it here. Good. Now at the second argument, we need to pass object, wet dollar set, Object, status, to scene. Let me check we pass that value in our schema or not. Oh, here we pass read. So stain this to scene because this is more user friendly. Save this and back to our event. Now, again, question is same. What do we want to do after we update messages as seen? Right, we will inform every sender whose messages are updated to SN. So here we need only senders ID because our jet ID is fixed, which we get from the front end. Because of this, it is a lot more easier than delivered event. So cost sender IDs is equal to tell me which method we use for extracting the new array from the existing array. Right, we use unseen messages dot Map. Here we get single message arrow function and we simply return message dot sender. This sender is object ID, so we need to convert it into string. Now, as we know, this map method collects all the chat IDs from the unseen messages, so we might get duplicate sender IDs in this array. We can solve that using set. We wrap this map method with parentheses and right here, new set. Will create set, and now to convert this set into array, we simply wrap it with square brackets and spread the set here. This map method will give us array with duplicate sender IDs. That's why we convert it into set. I set, we don't get to duplicate values, and after that, we again convert it in simple array. Now we have sender IDs, so we can simply do for loop const sender, which is the individual sender ID of sender IDs. Make sure here you use of not in because we use in for getting object keys, and we use of forgetting value from array. Previously, our group chat IDs is object. That's why we use in. But here, the sender IDs are array. That's why we use here off. I make this mistake before and it is really frustrating because I don't get the error and still code is not working the way I want it. So make sure you remember that. In this loop, we again do cost sockets is equal to online users dot get Sender. Here, we do same as before. If sockets are available, then sockets dot fe. Here we get single socket ID, arrow function, and inside it, we do Iot two, socket ID, dot m message scene. As the data, we send the chat ID to chat ID, and also we send the user ID who send those messages. Seen by two user ID, and that's it. You can see how simple it is. This is our first situation. Now let's implement second situation. In that, our user is already available in that room. We need to update status when other user send new message in that same room. So instead of writing logic in send message even we can emit the same mark messages as seen event from the front end when user get the new message in the joined room. So our end implementation related to status scene is complete here. Now let's simply taste this implementation. So in the front end, as we join a room, after that, emit here this event, mark messages as seen and pass here chat ID value. Also we have to emit the same event when we get the new message. In the GET message event, we add if condition data dot sender dot underscore ID is not equals to user dot underscore ID. This is the user ID of our logged in user. If this is true, then we do socket dot, Mark messages as seen. At the second argument, we pass at d dot value. See the changes and take a look. Let's refresh this window and pass here Harley's token. And also join the jet. And from the bottom, we send the message. This is for tasting scene status and send it. Now, if in our database, we check our latest message, see its status to send. And now if we open a new window, and login with my first account token. Now, again, if we check our message status, see it is updated to delivered. Now, I copy this chat ID, and from another user, I join this room. Now let's again check our database and refresh the data. See here we get message to scene and also that user will get data with chat updated and who seen that message is. So that's how we update status as seen using socket. 201. Adding Group Fields in Schema: Now let's add some ones features in our application. Currently, in our chat, we are implemented only one to one chat. Now let's add group chat also and we don't need to do much in it. First of all, we will add some group related fields in our chat schema. Here in the participants, we can add multiple users who are part of this group. After that, we also need last message, and after that, we pass this group and we set it to type to Bullion and default to false. Here we can add commands for groups. So when we implement group features, we can remember which fields we need to handle. Now, after that, group has admin, so admins, which can be one or more than one. We simply copy participants array with object ID and ref to user. Add it here. Next, what we need? Yes, we need group name, which is type to string, and also user can add group icon or group image, which is also type to string. I think this is enough for group chat. Also, here, make sure to not add required to true for group fills because if chat is one to one, then required to true for group fills can give us schema error. Now let's see what we need to do in the message schema. Here for group, we don't need to add much stuff. Just we need status for all group members. In group message, the status will not enough. So here we simply add filed delivery status, which is array, and inside, we will store objects for each participant's status. So first, user in object type mongs dot schema dot Types dot Object ID. Ref to user. This is each participant user ID. Also, for that user, we add status, so copy this same object from here and paste it inside this. Now, after that, we also need time when our message is delivered, delivered at type to date, and also we need seen at and also type to date and done, we don't need more fields. If in future we need, then we can definitely add them here. 202. Create a new Group API: Now let's create API for creating a new group. Here, we don't need to use socket for that. In the chat route, we can simply copy this create chat API and paste it at the bottom. Good. Now change the endpoint to create group. And in this function, we have to do little changes. First, at the place of receiver, we get participants array, which are the user IDs of participants. Also, we get her group name. For group image, we can separately add another API. And here we need to destructure the request body. Next, also, we change the condition. If participants is not available, then we return error message, participants are required. Now here we don't need to find any chat because same participants can have multiple groups. We simply remove this chat variable and as this if condition. And here we add const chat. Inside the object, we add participants to participants. But here we also need to add current user ID in the participants array. Here we add array and adhere user ID. Next, group name to group name. A is group to true, and we pass admins to array, and inside it, we pass current user ID. If in future, we need to add more participants or we want to remove participants, or we want to add new admins or update the group name, update the group image. For all of that, we can create separate APIs. For now, we don't need them because our main focus is to learn real time chat features. So let's test this API. For that, we open Postman. We need another user for adding them in group. So open register a new user API. Here, we pass another user name. John underscore 24, email to john at red gml.com, and password, I keep the same one to eight. You know why Because I forgot passwords. Good new user created. Now let's duplicate the create chat request and rename it to create a new group and point to slash API HATS slash Create Group. Also in the header, we already have token and in the body in the object, first we had participants to array here we add all users. From the database, we simply copy other two people's ID. Make sure you don't copy the object ID of your current account, which token you pass in the header. Good. Now, after participants, we pass group name, and what should we name the group? Let's say node ninjas. This is school name, right? Yeah, and send the request. See, here I get internal server error. Let me check what is wrong. In a terminal, we get error in participants. Oh, here I pass directly array inside array. So we spread the participants array, save the changes, and let's send the request again. See, here we create a new group jet. 203. Adding Group Chat Logic in Socket Events: Let's apply group chat logic in our socket events. First of all, we will start with send message event. Imagine here, user send a new message in a group. Now, in both cases, if user send one to one message or user send group message from the front end, we just need to pass content of the message and also the chat ID. So in our group chat, also, we check content is passed or not. Also, we find the jet by its ID. Next, we also create a new message with same object, but in group message, we have to adhere delivery status, select delivery status, and after that, we pass condition if jette group is true, then we need to create array of object which looks like this. So for that, we use delivery status is equal to jet dot participants dot Map. Here, we get user arrow function, and inside it, we simply return Object. Now in the object, user to user, and status to here, we pass condition. Online users doth user. If this is true, then we add status has delivered. As Sent. Also, we add delivered at two here, we also need the same condition, so we can add variable before this return. Cost online is equal to online users dot as user. Now at the place of this condition, we pass online and in the delivered at also, if user is true, then we pass new date, else, we pass null. Now here is one thing. In these participants, we also get the ID of sender and we don't want to add sender ID in the delivery status. Here we have recipients, which is the filter version of participants. So at the place of jet dot participants, we add recipients dot Map. By this, we don't need to update status explicitly at the bottom. After that, we also update the last status in the chat. Now here we populate Sendar data and emit get message event for the chat ID. Now also we populate the data, but here we also need to populate delivery status user because in one to one, we only use our global status, but in group chat, we have to display each user time. Here we add another populate method. At first, delivery status dot user, and what do you want to populate? Write underscore ID and user name. Now let's see what we need to do in Mark messages as delivered event. So as we know, making delivery status of log in user in group message is little confusing. So instead of using the same event, it's better we create a separate event for group message. So these mark messages, as delivered event is for only one to one chat. Also, in that, we need to do little changes. As we know, these chat IDs are all the chat IDs in which our user is available, but this will also include group chats. So here in the chat find method, we pass one more condition. Group to false, which means it will return only one to one jet, and that's it. We don't need to change any other thing. Now, let's create a new event. So socket dot on event, let's say, Mark group messages as delivered, and we pass here a synclwcFunction. Will call this event when our user logged in at front end, same as we emit mark messages as delivered event. Now, first of all, we need all the group jet IDs in which our user is available. Jet IDs is equal to await chat dot find. In comparison Object, we pass participants to user ID. Is group to true. And here we only want IDs. So which method we will use, right, we use dot distinct and pass here underscore ID. Now, after that, we need to find undelivered messages in this group IDs whose status is sent. So same as before, const undelivered messages is equal to await message dot find. Object, we pass chat ID to object, dollar in to chat IDs. Also sender to object, dollar N for naught equals to user ID, which is the logged in user ID. Now we need to also find those messages which are not delivered to current logged in user. So here we pass delivery status. To object, and as we know, delivery status is array of object with user and its status. We need to check user as our user ID and status is set to send. For that, we need to specify condition that must match within individual elements of an array. In our case, it is user and status. Don't get confused, see this. We can use here another Mongoiboperator, dollar Aleem, match to object, and here we pass user to user ID, and user status is must be sent. So by this image, we can specify condition even in the array of objects. Also, we don't need messages or information, so we simply addere dot select, and pass here underscore ID, jet ID, sender, and deliver datas. Great. Now, after this, we pass if condition undelivered messages that length is greater than zero. Only then we want to run update query. In this I log, we use four loop, const message of undelivered messages. And inside this four loop, we simply weight message dot update one. First, we pass comparison Object, underscore ID to message dot underscore ID, and in codes, delivery status dot user to user ID. At the second argument, we pass Object with dollar set to object first in codes, delivery status dot dollar dot status, two delivered. Here, this dollar dot status will help us to update only that fill whose user is user ID. Now, also, we want to add delivered at time, in codes, delivery status dollar dot delivered at, and we pass here new date. And done. This for loop will update status to delivered for all these undelivered messages. Now, what do we want to do after updating the messages? Right, we want to send the jet IDs which status are updated. So from our previous mark messages as delivered event, we can simply copy this whole logic after this update method. And paste it after the fall loop and also make sure it is also in the I blog. First of all, in this blog, we are creating object for senders and as value, we fetch the set of chat IDs which are updated. The reason we use here set is because it will remove all duplicate chat IDs and give us unique chat IDs. After that, we convert that to array, and at last, we run this fall loop for its sender from group jet IDs. And in this loop, we find socket IDs of those senders and simply emit event message status updated, and we pass that jet IDs to its related sender. So we don't need to change anything in this logic. You can see how simple it is. Just we need to clear what we want to do. Now let's move to last event, which is mark messages as seen. Here also, we create a separate event for Mark group messages as seen. Socket dot on Mark group messages as seen. And here we pass ASN callback function, and in the parameter of this function, we need Jet ID of that group. Now we copy the undelivered messages query from the group delivered event and paste it here. Now here we change undelivered messages to unseen messages, chat ID, to chat ID, sender to object, dollar NI for not equals to user ID, delivery status, image, user to user ID, and status is object, dollar, not equals to scene. Now we can pass I condition if unseen messages dot length is greater than zero, then we want to run update query. Again, we copy this four loop from the delivered group event and paste it in our seen event. Now here we change these undelivered messages to unseen messages, and in the update dollar set at the place of delivered, we market SN and also at the place of delivered at, we update SN at. Make sure you don't get error in any of these cli brackets. Be careful about that. Now what do you want to do after we update messages as seen? Simply, we copy the logic from the simple scene event. And paste it after our update query. Basically, here we face the sender sary of these messages, and using for loop, we simply emit message in event with chat ID and seen by, and that's it. Now let's test this implementation. Here, we open final SDML file in the browser, pass token for the user. Good. Now we need to join group chat. From the Mongo Di we compass in the chat collection, we simply copy our group chat ID and paste it in the chat ID, and join the room. Now let's send the message in this group. Hello, this is group chat and send it. Good. If we check our database, refresh the collection, and at the bottom, C, we get message, and in delivery status, we get empty array. Let me see what is wrong. Move to our send message event. Here in the new message, we forgot to add delivery status. So delivery status to delivery status, save the changes, and let's again taste or implementation. Refresh the browser, pass user token. Copy the chat ID from the chat collection and paste it in the chat ID and join the room. Now let's again send the message. Hello, this is group chat and send this message. Now if we again check our database, refresh the collection at the bottom, we get new message and in the delivery status, now we get status for each participants. Great. Now let's add another window open again SDMLFle here I add a token of different account. And the moment I hit Enter, see in our first window, we get notification your send message is delivered, which means our mark group event as delivered event is working. I refresh the database, see in the message delivery status, that user status is delivered, and also we get here delivered at time. Good. Now let me join the same chat. So go with this jet ID. And paste it here and join the room. See, in first window, we get notification your message is seen by this user. If we again check the database, refresh the collection, and at the bottom, see for that user, we update our status as seen and we also get the scene at time. This means our mark group messages as scene event is also working properly. It is so simple and not confusing because we separate the logic in different group events. So that's how we implement group chat in the socket. 204. Section 16 - Deployment Options: Welcome to the last section of the ultimate node hair course. In this section, we will see deployment process of node applications. So currently, our application is running on our local machine. Now to use our application globally, we need to deploy it. It is real easy thing. Don't worry about that. So there are two ways of deploying node applications. We can use pass, which means platform as a service, or we can use Docker. Now we might ask what is pass and Docker. So pass or platform as a service means we can use a platform which help us to deploy our application. PAS, we have Render, Eoco, Google Cloud Platform, AWS, Microsoft, Azure, et cetera. These platforms provide variety of functionality, so we don't need to worry much about deployment process. It's like, imagine you want to open a food stall. Now instead of worrying about buying a stove, setting up electricity, and getting water connections, you simply rent a fully equipped kitchen. Here you just need to bring your ingredients, cook your food, and start selling. That's exactly what PAS does for developers. With PAs, we don't have to worry about setting up servers, databases, networking, or skiing. These platforms take care all of that for us. We just write our note JS code, deploy it, and it runs. Simple as that. On the other side, if you want to control over your deployment or if you want to deploy your node application on your own web server, then Docker is a great option. With Docker, we can create an image of our application and deploy that image to any computer in the world. As you guess, using Docker is a little complex process. For now, we don't need to worry about that. So if you don't want to worry about servers, load balancers, infrastructure, or restarting your application on the crash, then platform as a service is a good option. So in this section, we will use render for deploying our node application because it has the easiest way of deploying node application, and also it provides a great features. Different people like different platform, but I think render is a great way of deploying and it has also free tire. So we can deploy our application for free and without any card details. 205. Simplifying the Code: Before deploying our application, let's make our index dot js file more clean and readable. It will create good impression on our team and also all of us like to work on clean code. Let's make this happen. Here, we create separate file for separate things, like for database connection, separate file. For routes, we have another file, and for socket, we also have separate file like that. It is really simple. Let's do this one by one. First of all, we separate the database connection. Here in our project, we create a new folder called startups. Inside this, we create a new file called DibtJs. Now in this file, we want to add code for database connection. Here, from the index dot JS file, cut the Mongoose dot Connect method. And paste it in our new five. Now here we need a couple of things. First, we need the mangos succed mongoose is equal to require mangos. Also, we need this logger, sconct logger is equal to require, we go one folder up, go to config, here we import Logger. Now, one question you might ask, how can we add this code in our index dot JS file? It is really simple. Don't get confused. Let me show you. Here at the bottom, we simply module dot exports is equal to. Here we add function inside this function, we simply move this Mongoose dot Connect method. Back to index dot JS file. Tell me how can we input something from the db dot js file? We use required forward slash startups DV. This expression, return whatever we export from this DB file and what we export function. We can store that in variable called const DB, and then we can call this function. Instead of doing this in two lines, we can simply do that in one line. Aropris of storing that function in variable DB, we can simply call it here. When we call that function, connection code will run, and that's what we want. So here our first step is done. Now let's separate all these routes implementation. In the startup folder, we create a new file called routes dot js. Also, same as before, we export module dot exports is equal to function inside this function, we add all our routes. So cut these all apps routes with app middleware as well course express dot Json and also Global error middleware. Them and paste them in our routes file. Now here we need a couple of things. First of all, we need this app and how can we get this app? Should we create a new app in this file and then use it? No, we can't do that because that will create a new Express application. But here we want to use our same application. What is the solution here? Solution is really simple. Here, from the index js file, after this DB, we had required period, slash startup, slash routes, which is our function. We call this function and simply pass app as argument. In our routes function, we simply get app as parameter. Next, what we want? We need course and how can we get yes, we can use the same way. But as we know, course is our package, and we can use package in any file by simply input. With app, we can't do that, only that's why we get app as parameter. So at the top, Cost course is equal to require Cos. Also, we need express, which we can also import here. Cost Express is equal to require express. Now after that, we also need logger, sconct, logger, is equal to require, we go one fuler up, config, and logger. Now, next, we need these routes, SeconstUser routes, is equal to require. Here, we also move one folder up routes users. Now duplicate this line two more times using alter plus sift, plus down arrow or option dot Sift plus down arrow. Here first, we change the variable name to post routes and file to post. Next, we change the variable to chat routes and file to chats and that's it. We're done with Step two. Now let's separate our socket logic. From this online users variable, we select our code to till we get server dot LISN. Cut this the startup folder, we create a new file called socket dot js. In this file, we again module dot exports is equal to function. In this function, we add our code. Now, first of all, here we need this AO method. Tell me, should we create a new Ao object? We need to use that same Ao object which we created using server. In index dot js file, we had required period startups socket. And here we call this function and simply pass here Ao Object. In socket dot js file, here we get the Io object a parameter. Simple as that. Now in this logic, we have to import a lot of things, so don't try to hurry. Let's go line by line. See, in this ous, we need this JWT. At the top const, JWT is equal to require JSON web token. Next, what we need. Yes, we need this chat model, and also we need this message model. So at the top, cost chat is equal to require here we go one folder b models chats. Also, if you get confused in importing file, then let me show you my trig when I'm importing file. Here we want to import message model. Cost message is equal to require, first of all, I collapse all the folders using this button, and then I simply open the folder in which I am working. Is startup, and also open folder from which I want to import. That is models. Currently, we are in the Stu folder. We need to go outside of that folder, so we add period, period forward slash. Then we want to go in Models folder, and we import from messages model. See, it is that simple. Now let me see what else we need to import. I think that's all we need. If we miss something, then we get error. Don't worry about that. Now let's see how our index Dsi looks. See, it is clear now, but let's make it more clear. Here we have a lot of unused inputs. We can remove them. First, we remove code input line, so press Control plus X or Command plus X to remove that whole line. So we remove Mongos and remove all carried out imports which all are not used. See, now our code looks more clean, easy to scale, and we all love to work with this type of clean applications. This is how professional developers code should look like. 206. Preparing Node app for Production: Now before we start the deployment process, it's better we prepare our node application for production. So for that, we need some packages like first one is helmet. We already use that in our previous project. Basically, helmet is used for security of our application. It is an excellent option to enhance the security of our app with minimal configuration. Also, it protects our app from common web vulnerabilities setting proper STDP headers automatically. In our terminal NPM install helmet and if you want to use the same erson as mine, then you can use at the rate 8.1 0.0 and hit Enter. Now another package is compression. This is also very useful package for node applications. As we know, sometimes we have to send big size data to many users. For example, list of post or list of messages. This package will compress that big size data and reduce load of sending big data. So NPM install Compresson at the d 1.8 0.0 and hit Enter. Good. Now, let's implement these packages in our application. Don't worry, it is just two lines of core. So here in the starter folder, we create a new file called prod dot js. In this file, we import these two packages. So const, helmet is equal to require helmet and const, compression is equal to require compreson. Same as before, we export function from this module. So module dot exports is equal to here we export function. Here we get app as parameter, and inside it, we want to implement this middle was. App dot U helmet which is the function, we call it. By this only helmet is applied in our application. Also we add app.us compression, and we also call it and done. By these two lines of code, we apply these packages in our application. Also, you can add this code in route dot js file. There is nothing wrong about that. Now here we just need to import this module in our main index dot js file. Here before these routes, we simply require period databsPd which will return that function. So we have to call that function and simply pass your app as argument. Make sure it is added before this route imports. So our helmet and compression apply for all routes, and that's it. By using those two lines, we can make our application little better. 207. Overview of Deployment Process: Let's see the overview of the deployment process so we don't get confused. Currently, our code is available in our local machine, or we can say in our computer. Now to make our application live on the Internet, we use render platform. First of all, we will upload our code on Github, and then we connect our Github repository with our service, which is render. Don't worry about that. It is really simple. I will explain all steps in simple and easy way. Also, we will see how to update our code after we deploy our application. Let's start with uploading node application on Github. 208. Uploading Node application on Github: Let's see how we can upload our project on Github. If you don't know Github, in short, it is a website that allows developers to store, share and collaborate on code with other developers. Also, Github allows developers to create repository or we can call repos where they can store their code and track changes over time. This is the best and easy way for teams to work together on a same project without overwriting each other's code. So there are many ways to upload our code on Github, but we will see the easiest and the simple way, which is by using Github desktop application. Head over to Browser and search Github Dektop application and open this first link. Now click on the Download button. This will take some time. And after completing this download, open the setup, and our installation process is started. Good. Now, if you open this application first time, then you have to login with your Github account. So to show you this, I remove my Github account from Gitub desktop application. Now to login, go to file and open Options and click on this sign in forgitub.com. Continue with browser. This will redirect us on GitubOficial website, fill your user name and password of your Gitub account and click on sign in. I have to verify my account and done. And now click on this Open Github desktop application. It will automatically redirect us on our application. Don't worry, you need to only set up for the first time. Now let's verify we logged in or not. So again, go to file and Options, and in the accounts, we can see we have our accounts. Go to the Git option, and from here, we can set our name and email for our Github. So when we push code on the Github, other team members will see this name and email. Also make sure you select your official email here and click on Save. Now, before we move forward, as we know, in our project, we have node modules folder. We don't want to post this on Github because at any time, we can generate node Module folder using NPM install command. So it is useless, we upload whole node modules folder, which has a lot of files. So we have to ignore that folder from getting upload on Github. For that, in our project at the root, we create a new file called dot git ignore. Make sure you don't make any typo in this file name. It should be dot gitignore. Now in this file, we can add which files and folders we want to ignore or in simple words, which files and folder, we don't want to upload on Github. Suppose we want to ignore this node modules folder, so we write node underscore modules, which is the folder name and forward slash, which indicates this is folder. Similarly, we want to ignore logs folder. So what we write? Write Logs forward slash. Now here is one thing. When we upload our code on Github, as we know, this code will become public and everyone can see our project. Now suppose we upload our project and this donVfle also get uploaded on Github. By that, our all secret information will become public and anyone can misuse it. So we have to also add this dot NV file and gitignore. Let me show you short cud for getting Gate Ignore file. Simply go to your browser and search, Get Ignore, Github. Open this first link, and here we get all templates for different types of application. Have Android Git Ignore. Also, you have C plus plus, C, and many more files. Now search at the top, node gitignore and open this file. See, here we get the content of the GetI Nur file. Simply copy this code and add that code in our GetI Nur file. Save the changes, and we have our GetI Nur file. Cool. Now let's finally upload our code on Github. For adding our code to repository, go to File and select Add Local repository. And here we select our path of our inkifi application. Now here it says we have to create a new repository, so click on that link. And here we have to pass our repository name. Also, we can write here description. This is the social media application and click on Create repository. Now let's verified we had right path or not. So click on show in Explorer and see here we get our Linky five folder, so close it, and simply click on Published repository. Here we can change the repository name and description, and also we can select the privacy of code. Also, you can make it private, but I want to give you this code. That's why I make it public and click on Publish. It will take some time and done. Let's see it on Github, so click on view on Github and see here we get our application. Lovely. You can see how simple it is to upload code on Github. Now in the next lesson, we will set up our render account. 209. Deploying Node App on Render: Let's deploy our backend application on Render. So head over to render.com, and first of all, we will register our account here. We can use Google or Github for registration or we can simply use email and password, and we got this dashboard. Don't worry about that. Simply click on New button, and here we select web service. Now here we need to connect our Github account. So Glicon connect Github and login with your Github account. Make sure you use the same Github account in which we publish our backend code. From this page, we can select which repository we want to add in our render account. You can also add all repository, but in my suggestion, select only selected repository option. From here, we can select repository, so we can select our inkifi application. Now, this will redirect us to the dashboard home. See, now we get here our repository. Simply, click on this repository, and here we get our form. Now, first of all, here we add our application name, which is our Linkifi. We will get this name as our base URL of our application. Next, we have environment which is set to node. Don't change that. Next, we can select branch of our Github repository which is main or master. Also, we can select region. Now for root directory, we add period, and for build command, we write NPM install. For start command, we simply add node index dot js. Basically, by this command, render will run our application. From bottom, we select our service type which we select for free. Now click on this Advanced drop down and select Add Secret File and give it a name dot and V. Now back to our wagon project, and in that we open DotynVFle in which we have our secret variables. Simply copy all code and in Render website, click on Contents and paste our code here. Now just click on Create web service and see our deployment process is started. It will take some time like five to 10 minutes. C, build successful. Now it is deploying and after that, I get error in one goody B connection. Let me check this. It is error related to DB variable. I think I made mistake in adding secret file. So here we go to the environment tab, and here, let me check the file contents. It is good. Oh, here I enter wrong file name. It should be dotnV. I intentionally create this error because I want to show you how to check environment for a bus. S the changes, and back to Logstb. Here, it will again start the deployment process. And see here we again get error in database connection. Why? So currently, our database is local database, which means it is working in our local machine. Now when we deploy node application, we can't access local database. So at that time, we have to add Cloud database, and we will do that in the next lesson. 210. Adding MongoDB Cloud: Currently in our back end, we have local Mongo Debe database, so we have to create our Mongo Dibe database in the Cloud. By that, all users will use the same database. So head over to mongotib.com and simply sign up with your account. It will take only 1 minute to set up. I already sign up, so here I try to log in with my account. Thank God, it's open. Now at the top left corner, here we get new Project button. Click on that and here we write our project name, which is our Linky fi and click on next. Now from here, we can add team members to our project. Just click on Create Project. Now click on Create button. Here, we select plan, simply go to free version and click on Create Deployment. And see here we get our username and password for our database. So I copy first username and in note paid, paste it here. After that, also copy this random password and paste it also. This is the most important step. We can save this user name and password as backup of our database. Now click on Create database. Next, we click on, choose a connection method. Select here Compass. See, here we get Mangaib Connection URL for Cloud. Don't worry, just simply copy this database link and in our ENV file at the place of this local Mangaibi ink, we paste our MongoibCloud link. Also, here I forgot to add a database name at the end of this URL. So make sure you add it like this. Okay? Now let's continue. We have to give access to network which can read and write data in our database. From anywhere, user can access our database and get post from it. In the left side, go to Network Xs. Here we have our current address. Click on Edit and simply click on Allow access from anywhere. You set our address to 0.0.0.0, which is the aces for every one and click on Confirm. This will take little time and see it is active. Good. Also, if you want to check the database access related setting like editing password or something, then you can do that from this step. Now, let's verify it is connected or not. So open up terminal and write node, index dot js, and hit Enter. This will take some time and we get go to be connected successfully, so it is working. Now we have to update our deployed code. How can we do that? Simply, we just need to push our code to Github and render will automatically detect those changes, and that's why we add no project to Github. Now here is one thing. We know we ignore this Dotty and V file from uploading on the Github. For updating the environment variable values, we need to go to the render website. Here we select environment variables. Click on edit and simply from here, we can edit our values. I replace database URL to Cloud. Here also, you have to add your database name at the end of this URL. Now, click on, save, rebuild, and deploy. Good. If we check our logs, after some time, we will get again deploying log. And see here we get Mongo to B connected successfully. Lovely. Now, let's taste our application is actually working or not. So here we copy Cspace URL of our deployed application. Now open postman, and in this, we duplicate this create new user API because we just create the fresh database, so we don't have our previous data in it. Now let's change the local host URL with our deployed application URL and send the request. See, here we get JWT Token, which means our API is working. Let's verify that. On Mongo Deb website, go to our Linkify app here we get Browse Colection and see, here we get all our collections, and I we check user collection. See, here we get the new user. Lovely. But wait, while I'm getting here taste database name. I think I forgot to add database name in the collection URL. Go to environment variables, click on Edit. And yes, after this URL, I add forward slas and here I add database name. Let's say, our Linky fi and simply click on Save, rebuild, and deploy. It will rebuild our application, and at the end, we connect with our database. Let me again taste the API, send the new user request, and here I get new token. Good. Now go to Mongoib website and refresh the database. See, here I get our inkifi database. Great. Now let me also show you how can we update our code and redeploy it. So in our project, what we can change? Let's this Console message, server is running on portar PT. This is just for demo, save the changes and to update the code on render. We have to just push our code on Github, render, will automatically fetch our updates and redeploy it. So back to our Github desktop application, and here we pass Commit message. Let's say, update Console message and click on Commit one file to main, and at the end, simply push origin. Now in our render website, we go to the deploy section, and here after one to 2 minutes, we can see it is deploying and at the end, we get server is running on port Our port, which means our code updated successfully. You can see deployment process is really simple and easy. Just you need to upload your code in Github repository and then by using render, we will deploy our application quickly. And if we want to update our application, then we just need to push the changes on the Github and in the two to 3 minutes, our server will restart and we get our updates. 211. What is MVC Architecture? [BONUS]: Now if you are working as developer, then you have definitely hear about MVC architecture in big projects. So let's see what is MVC architecture and why we need it. So MVC stands for model view controller. Basically, it is a way of organizing our application core. So in the future, it will a lot easier to manage, maintain, and scale the application. In simple words, it is a folder structure which separates different parts of our application. In MVC architecture, we create three separate folders. One for model, second for view, and third for controller. Don't get confused. It is really simple. So model folder is where our data lives. Here, we have to define how data should be structure and how to interact with your database. For example, in Node application, we already created models folder, and in that we store all the models and schemas for each Mongo be collection, and that's why we name this folder as models. Next, we have view folder. View means what the user sees. It is the UI part of our application. For example, in the Node application, we might have template engines like EJS or PUG or we have SDML or CSS files, which we want to display. So if we have front end related code, then we can store that code in the view folder. Now at last, we have controller folder. In Controller folder, we will store the logic of our application. For example, if we open our user's route, here we can see this is ASN callback function, which runs when someone send post request on this endpoint. This is the logic part. In Controller's folder, we will store the ASN functions separately, and then we will just import it here in the routes. Don't worry, we have to simply cut and paste these functions. We will see that in just a minute. Here we understand MVC model for data, view for UI related things, and controller for the application logic. But you might ask, what is the point of this MVC architecture? Why big companies like it? So as we know in big companies, there are big teams are working on one application. If we create separate folder for each part like model, view, and controller, then it will create separation of concerns. Here by separation, our code can easier to manage. Suppose one team works on the post related features, second team works on payment related features, and another team works on the user related features. Each team did not need to touch post model file or payment model file or user model file. They will work on their separate features, and that's why when they push code on Github, it will not come up with big conflicts. Also, another benefit of MVC is it is easy to maintain. We want to update model, then we don't need to update view files. Another benefit is it is much easier to scale. As our app grows, it is easier to add new features because everything is already well organized, and this is why big companies and nowadays freelancers also low this MVC architecture. Now here is the folder structure for the MVC architecture in Node JS. First one is our main project folder. After that, we add index dot JS file, which is our main file. Also, we add other files or folders like package dot sn file or dot ENV file or middleware folder, you stay here in the main folder. After that, we add models folder in all models we store. Next, folder for all the UI related files, and then Controllers folder for all the logic part, and in Node JS, we have routes folder. So we will add all routes in this folder. Now, this folder structure is good for small or medium sized projects, but big companies like Paypal and Netflix use little different folder structure. It's definitely on you and your company which folder structure you select. I will show you both options. This another option is a little different and it is good for Big Bend applications. Here we are main project folder. In that we had index dot JS file, which is the main entry point of our application. Also, we at ENV files, package dot JCNFle Docker files, and UploadedFles, and folders we store here. After that, here we add another folder called source or SRC here we can store our middleware folder, convey folder, and Utils folder, et cetera. Also, in the SRC folder, we store modules folder for each module, and in this folder, we can add folders for each feature like user folder, post folder, et cetera. In this each folder, we can define three files, user dot model dot gs user dot routes dot js, and user dot controller dot js. So we can add one more file user dot service dot js. This file is not compulsory, but some companies like to use that. In this service file, we can store database query. It is not compulsory to add this user dot service dot js file, but some companies like to add it. So like this, we can add four files for post folder also. When we want to add new feature like product, we create folder product here in the modules folder, and then we can add four files in the product folder. As we can see, this is much complex, but it is really good for big and complex applications. You can use whatever you want to. It's totally up to you. Folder structure can be a little different for company to company. Don't worry about that. Now in the next lesson, we will apply MVC architecture in our application, and then we deploy those changes. 212. Apply MVC Architecture [BONUS]: Now, let's apply MVC architecture in our Linky Fi project. So currently in our application, we have very organized structure, like we already have models folder and Routes folder. Here, we don't need view folder because there is no template engine code. So we need to do just little bit for manage it. So let's do this. First of all, here we create folder called SRC. N S like this config folder, hold Control or Command key, select it till Stu folders. Make sure you don't move these Node modules folder. Good. Now let's see what we have to change in the index JS file. Mostly, we have to change the input file parts. See, here we have these startu paths. We have to update it. Here we create multiple cursor by holding alter or option. And add here SRC, to make sure we are getting this file or not, let me check by removing this file name. See here we are getting file suggestions, which means it is right. Now we don't need to change anything in the index to JS file. Now in the SRC folder, we already have models and Routes folder. But as we know, we apply here. Complex Node application structure. So here, we create a new folder called modules. In this modules folder, we have to mainly create four folders because here we have four models. Let's create first folder called Jet, then another folder called message. Then another folder for post and last folder for user. Now remember in each folder, we have to create three files. So let's do that. First, we move user JS file from the models folder and did in the user folder. Here we rename its file name to user dot model dot js. Here, it may ask for update inputs. Make sure you click on, yes. And if you are not getting that menu, then you have to do it manually. Now let's move users dot js Route file from the routes folder and d it in the user Module folder. Now it is asking for update. Tell here to Update user dot js Route filename. Now let's rename this file to user dot routes dot js. See, now it is not asking for update. Don't worry, we will update that manually. Now in the user module folder, we create one more file called user dot controller dot js. Now you might ask what we will add in the controller. Controller is where we store the logic of our application. It is a collection of callback functions of our APIs. Let me show you that. Here in the user's route, we have first register API, and this is its callback function. This is the controller for this route. Cut this callback function from here and in the controller file, we have to export this function. So Cast register user is equal to and past this callback function here. Now to export this function, we add module exports is equal to object because from here, we want to export multiple functions. So here we can add registered user to register user, or we can remove this. Save this file, and now we have to add this function in the user's route. So at the top, we add cost user controller is equal to require here we import from dot forward slash user dot Controller. Now at the place of API CallwayFunction, we simply add user controller, dot register user. Make sure you don't call this function here, we have to add function reference. Now let's do the same for other APIs also. So cut this login API controller. In our file, we define a new function, cost login user is equal to paste callback here. Next, we got this API callback function. And in our controller file, we create a new function. Cost, get user is equal to paste it here. Same as this, we have to cut each callback function and separate it in the controller file. I know this is a little worrying, so put some music and we can complete this together. Cut the callback function, and in the file, Cost, request, reset password is equal to paste it here. Cut the next callback function, and in the file, Cast reset password is equal to paste it here. Cut the next callback function for follow the user, and in the file, Cast, follow user is equal to paste it here. Now cut the next callback function, for reject, request. In the file, Cast, reject, follow, request, is equal to paste it here. Now got the next ColbkFunction for accept request, and in the file, cost except, follow request is equal to past it here. Cut the next callback function, for follower list, and in the file, const, get other user, follow, list, is equal to paste it here. Don't worry, we have only few left. Cut the next callback function, for following list. And in the file, const, get other user, following list is equal to paste it here. Cut the next callback function. And in the file, we add cost and follow user is equal to paste it here. Also, back to route file, we need this general Cs function for register and login API. So we also cut this whole function and paste it in the controller's file. Here you might have updated generate tokens function for excess token and refers token both. Here I have my old code because those are updates after I publish the course, but don't worry, it is the same process, cut that whole function and dt in the controller's file. Also, if you have refresh route and logout route, then do the same for those APIs also. Here, we just need to export these functions and then add them in the Routes file. So after register user, we add login user, get user request, password reset, reset password, follow user, reject, follow request, accept, follow, request, get other user, follow list, get other user, following list, and last unfollow user. Save this file, and in our route file, we addeeUuser controller dot login user. I'm not destructuring the functions here because if some new developers view our code, then he or she can get confused. Now, user controller dot god user, user Controller, dot request password reset, user controller dot reset password, user Controller dot Followser user Controller, dot reject, follow, request, user Controller, dot accept, follow request. User Controller, dot get user, follow list. Next, user Controller, dot get other user, following list, and last, user Controller, dot unfollow user. Now we have to import necessary things for these controllers. At the top, we can see all unused imports which grade out. So we can collect them together by moving the sauce down and simply cut those imports and paste them at the very top of the controller file. Good. Now here, we have to update the user model path, so we change it to period slash user dot model because it is in the current folder. Also, we can make sure these paths are okay. Yes, these are okay. Save this file. And if we check our route file, see this looks very clean. By this way, we can very clearly see API endpoints with API methods. Now we have to do the same for jets and post also. Let's quickly do that. First, we move jet model in the jet Module folder and rename the file name to chat dot model dot js. Let's move chat route in the chat modules folder, update input. Now rename the filename chat dot Rous dot js. Now we have to create new file for chat dot controller dot js. Back to Routes file. First, we cut this first API callback and in the controller file, we create a new function. Cost get chats, is equal to paste it here. After that, we cut the next callback function, and in the file, Cast get chat messages is equal to paste it here. Next, cut the next callback function, and in the file, cost, create chat is equal to paste it here. Next here, we don't need the send message API because that we have handle with Socket. We can remove this good now got the next callback function and in the file, cost create group is equal to paste it here. Now we have to export these functions from here. At the end, module exports is equal to Object, Gchat to GchatsO we can remove the getchat messages, create chat, and create group. Save this and in the route file here, we input cost, chat controller is equal to require here, parlas chat dot controller. Now in our APIs, we will add those functions. So chat controller, dot GAD jets, chat controller, dot get messages, chat controller, dot create chat, and last chat controller dot Create Group. Now we cut these model imports from here, save this file, and in our controller file at the very top, we paste. Good. Now here, we have to also update these two models path. So we change the chat model path to period forward slash chat dot model, and for message A, we will add message model in the message Module folder. So we go one folder up message slash message dot model. Save this file and we have to move message model in the message Module folder. Now change the file name to message dot model dot js. Now we have to just do this process for our last post module. First, we move post Model in the post Module folder and rename the file name to post model dot js. Now let's move post route in post Module folder, update input, rename the filename, post dot routes dot js. Good. Now we have to create new file for post dot controllers dot js. Back to Routes file. First, we cut the first API callback and in the controller's file, we create a new function. Cast create post is equal to paste it here. After that, we cut next to callback function and in the file Cast, get my post is equal to paste it here. Next, cut the next callback function. And in the file, Cs get following post is equal to posted here. Next, we cut another API callback function. And in the file, const, delete post is equal to, and paste it here. Don't furry only last few functions to go. Cut the next Colbeg function for like and dislike the post. And in the file, const, like, unlike post is equal to, paste it here. Cut the next Colbeg function. And in the file, we add cost, add comment is equal to paste it here. Cut the next callback function. And again, in the file, we add cost, add comment, reply is equal to paste it here. And now for the last API callback function, cut it and in the controller file, we add cost, delete comment, is equal to paste it here. Now we have to export these functions. Module dot exports is equal to in object, create post to create post, get my post. A following post, delete post, like like post, add comment, add comment reply, and delete command. Save this and in the post routes file at the top, we add cost post controller is equal to require period forward slash post dot controller. Now in our API, we can add those controllers, copy post Controller and write, postcontroller, dot create post, postcontroller, dot GET MyPost, post Controller, dot GET following Post, post Controller, dot delete Post. Post controller, dot, unlike post, post controller, dot add command, post controller, dot add comment reply, and post controller dot delayed comment. Good. Now let's cut the unused imports from Routes file. Save this file and in the controller's file at the very top, we paste it here. Now here, we have to update these two paths, period, forward slash post dot model, and for user path, we go one folder up, user folder, shuser dot model. Save this as we can see, our files look more organized. So here our models and routes folder are empty now, so we can simply delete them, and I think we have to update path at one more place, which is routes dot Jsle in the startup folder. See here path didn't get updated automatically. So here we simply change the path to modules, user, slash user dot Routes. Modules post post dot routes and modules JET Jett routes, and done. Great. Now, let's quickly push this code to Github. And by that, our code can automatically get deploy. So open Github desktop application. And here we get all changes. Write the commit message. And commit it. And at last, we simply put this code on Github, and that's it. This will automatically get deploy. So this is how in professional world, big companies manage their no JS code. Also, there may be a little different approach depends on companies or team you work with, but this is the most common folder structure which professional developers use nowadays.