0% found this document useful (0 votes)
32 views116 pages

Backend Notes

The document outlines a multi-day training program focused on Node.js, covering topics such as npm, callback functions, core modules, server creation, and database integration with MongoDB. It explains the importance of package.json and package-lock.json, introduces JSON for data exchange, and details the use of Mongoose for easier database management. Additionally, it provides practical coding examples and analogies to facilitate understanding of web development concepts.

Uploaded by

vvsdvdsxy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views116 pages

Backend Notes

The document outlines a multi-day training program focused on Node.js, covering topics such as npm, callback functions, core modules, server creation, and database integration with MongoDB. It explains the importance of package.json and package-lock.json, introduces JSON for data exchange, and details the use of Mongoose for easier database management. Additionally, it provides practical coding examples and analogies to facilitate understanding of web development concepts.

Uploaded by

vvsdvdsxy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 116

DAY 2

● Learn npm init

● Understand Package.json

● Package.json – ensure a list of packages with their version


● // Analogy: list of clothes you want to purchase with size and all, it also
consists of other metadata like name and all.

● Package-lock.json — ensure detailed of every package installed with


version, sub dependencies, store detailed, discount everything…
● it's like a detailed billed

● Both files work together to ensure smooth development for you and your
team.

● Understand Callback Functions

● Let’s understand First the Functions, Like Different ways to write functions

● Then callback Functions


● It’s like a function calling different Functions
● Core Modules of NodeJS

● There are many built-in modules in Nodejs that we can use


● https://nodejs.org/api/

● Learn about the ‘fs’ module


→ It creates a file and writes the message inside

● Learn about the ‘os’ module


● → Learn os.userInfo()
● → Log username

● Write a username into a Txt file with the help of the ‘fs’ system

● Console.log ( ‘module’ )
● → It gives the result of all modules we can do with that file in the nodeJs

● fs.appendFile(filename, message, callback);

● Import Files from

● Now create a notes.js


● Import file
● console.log( ‘notes is starting …’)

● Module.exports.age = 5;
● module.exports.addNumber = function(a,b){}
● Npm Package - lodash

● npm i lodash
● Widely used library
● Lots of functions which helps deal with data.
DAY 3

● Server in Nodejs

● Server – A server is a Person who communicates with clients


● Analogy → server = waiter
● Analogy → chef = database

● A server is a computer program that's responsible for preparing and


delivering data to other computers
● web pages, images, videos, or any additional information
SERVER

JSON: JavaScript Object Notation

● Imagine you're sending a message to your friend, and you want to include
information like your name, age, and a list of your favorite hobbies.
● You can't just send the message as is,
● you need to organize the information in a way that both you and your friend
understand.
● JSON is a bit like this organized format for exchanging data between
computers.

● JSON is a lightweight
● Structured and organized Data because
● in most contexts, JSON is represented as a string

{
"name": "Alice",
"age": 25,
"hobbies": ["reading", "painting", "hiking"]
}
● Inter Conversion JSON to an Object in Node.js:

const jsonString = '{"name": "John", "age": 30, "city": "New York"}';


const jsonObject = JSON.parse(jsonString); // Convert JSON string to object
console.log(jsonObject.name); // Output: John

—---------------------------------------------------------------

const objectToConvert = { name: "Alice", age: 25 };


const jsonStringified = JSON.stringify(objectToConvert); // Convert object
JSON string
console.log(jsonStringified); // Output: {"name": "Alice", "age":25}

● ADVANCED ARCHITECTURE OF WEB FLOW


● What are API and Endpoints?

● Imagine a menu card in a restaurant


● Lots of options are there, each option will give you a different order
● Now, collection of that list = Menu card = API’s
● And an option in that list = Endpoint
● And the waiter only understood whatever things are written on the menu
card

● Create a server

● Creating a server in NodeJs via express package

● Express.js is a popular framework for building web applications and APIs


using Node.js.
● When you create an Express.js application, you're setting up the
foundation for handling incoming requests and defining how your
application responds to them.

● Now we are going to create a server == waiter


● Now the waiter has his own home?

In simple terms, "localhost" refers to your own computer. After creating a


server in NodeJS, you can access your environment in ‘localhost’

● Port Number?
● Let’s suppose in a building – 100 rooms are there, for someone to reach he
must know the room number right?
● Methods to share data

● Now, in the world of web development, we need to deal with data


● How data is sent and received between a client (like a web browser) and a
server (built with Node.js)

● So there are lots of methods out there to send or receive data according to
their needs.

● GET
● POST
● PATCH
● DELETE

● GET

● Imagine you want to read a book on a library shelf.


● You don't change anything
● you just want to get the information.

Similarly, the GET method is used to request data from the server.

For example, when you enter a website URL in your browser,


your browser sends a GET request to the server to fetch the web page.
● Code that we have written on the videos

const express = require('express')


const app = express();

app.get('/', function (req, res) {


res.send('Welcome to my hotel... How i can help you ?, we
have list of menus')
})

app.get('/chicken', (req, res)=>{


res.send('sure sir, i would love to serve chicken')
})

app.get('/idli', (req, res)=>{


var customized_idli = {
name: 'rava idli',
size: '10 cm diameter,
is_sambhar: true,
is_chutney: false
}
res.send(customized_idli)
})

app.listen(3000, ()=>{
console.log('listening on port 3000');
})
DAY 4

● Database

● Web development = client + server + database


● Ultimately, Let’s suppose we are going to open Restuarant and there is lots
of data around it,
Number of chefs
Each Person's Detail ( like chef, owner, manager, waiter )
● Name
● Age
● Work
● Mobile number
● Email
● Address
● salary
Menu Details ( like, drinks, Snacks, main course )
● Name of dish
● Price
● Taste ( like, sweet, sour, spicy )
● Is_drink ( boolean true, false )
● Ingredients ( array of data – [ “wheat”, “rice”, “sugar” ]
● Number of sales ( like 76 )

● This is all Data we must have to store to run a fully functional restaurant
● So we have to deal with data

● Now There are lots of Database out there in the market, we can use
according to our need
○ SQL
○ PostgreSQL
○ MongoDB
○ MariaDB
○ Oracle
● Databases typically have their own server systems to manage and provide
access to the data they store.
● These database server systems are separate from Node.js servers but
work together to create dynamic and data-driven web applications

● Node.js Server and Database Server:

● A database server is a specialized computer program or system that


manages databases. It stores, retrieves, and manages data efficiently
● The database server stores your application's data. When your Node.js
server needs data, it sends requests to the database server, which then
retrieves and sends the requested data back to the Node.js server.

● Node.js server is responsible for handling HTTP requests from clients (like
web browsers) and returning responses.
● It processes these requests, communicates with the database server, and
sends data to clients.
● Setup MongoDB

Q) So as We are creating a backend server, as same do we need to create a


Database server as well?

Ans) NO

—> Setup MongoDB locally is quite tough for most of you. But relax we are
here to help you

● Go to MongoDB's official website


● Or Google MongoDB download

For MacOS
https://stackoverflow.com/questions/65357744/how-to-install-mongodb-on-apple-
m1-chip

For Windows
https://www.geeksforgeeks.org/how-to-install-mongodb-on-windows/

—- Trust me Give some time to it until you will download the MongoDB in your
system. There is no point to move ahead without installing MongoDB
● MongoDB Syntax and Queries

Now As we know there is 2 thing, MongoDB


● → Start MongoDB Server
● → now we can use MongoDB shell from where we can interact with
databases
1. Create a Database:

In SQL:

CREATE DATABASE mydb;


In MongoDB:

use mydb;

2. Create a Table (Collection in MongoDB):

In SQL:

CREATE TABLE users (


id INT PRIMARY KEY,
username VARCHAR(50),
age INT
);

In MongoDB:

db.createCollection("users");

3. Insert Data:

INSERT INTO users (id, username, age)


VALUES (1, 'Alice', 25);

In MongoDB:

db.users.insertOne({ id: 1, username: 'Alice', age: 25 });

4. Query Data:

In SQL:
SELECT * FROM users WHERE age > 21;

In MongoDB:

db.users.find({ age: { $gt: 21 } });

5. Update Data:

In SQL:

UPDATE users SET age = 22 WHERE username = 'Alice';

In MongoDB:

db.users.updateOne({ username: 'Alice' }, { $set: { age: 22 }


});

6. Delete Data:

In SQL:

DELETE FROM users WHERE id = 1;

In MongoDB:

db.users.deleteOne({ id: 1 });


● MongoDB Compass GUI

● There are lots of Tools in the market that help to visualize data like
mongoDB compass, MongoDB Robo 3T
● mongodb://127.0.0.1:27017

● Data Desing and Postman

● Now in order to use the database we have to integrate MongoDB with


nodejs
● Now, there should be a form built on ReactJS or HTML or CSS to add chef
or person details
● Now currently we don’t have a such frontend thing, so we are using
Postman for this
● Every Frontend Application, collect Data format it according to backend
Requirements and then will send it to backend APIs

● Let’s suppose creating Dummy Data for Person


● Each Person's Detail ( like chef, owner, manager, waiter )

{
"name": "Alice",
"age": 28,
"work": "Chef",
"mobile": "123-456-7890",
"email": "[email protected]",
"address": "123 Main St, City",
"salary": 60000
}

● Each Menu’s Detail

{
"name": "Mango Smoothie",
"price": 4.99,
"taste": "Sweet",
"is_drink": true,
"ingredients": ["mango", "yogurt", "honey"],
"num_sales": 45
}
{
"name": "Spicy Chicken Wings",
"price": 9.99,
"taste": "Spicy",
"is_drink": false,
"ingredients": ["chicken wings", "spices", "sauce"],
"num_sales": 62
}

● Connect MongoDB with NodeJS

● Now, To connect MongoDB with NodeJS we need a MongoDB driver (a set


of programs)

● A MongoDB driver is essential when connecting Node.js with MongoDB


because it acts as a bridge between your Node.js application and the
MongoDB database.

● MongoDB speaks its own language (protocol) to interact with the database
server.
● Node.js communicates in JavaScript.
● The driver translates the JavaScript code from Node.js into a format that
MongoDB can understand and vice versa.
● The driver provides a set of functions and methods that make it easier to
perform common database operations from your Node.js code.
● The driver helps you handle errors that might occur during database
interactions. It provides error codes, descriptions, and other details to help
you troubleshoot issues.

● The most popular driver is the official MongoDB Node.js driver, also known
as the mongodb package.
npm install mongodb
● Mongoose

● Now but we are going to use Mongoose, rather than mongodb

● Mongoose is an Object Data Modeling (ODM) library for MongoDB and


Node.js
● There are lots of reasons we prefer Mongoose rather than a native official
driver
● Things are a lot easier here
( Relate Real life Examples with mobiles with earphones )

● Mongoose is like a translator between your Node.js code and MongoDB. It


makes working with the database smoother and easier.

● With Mongoose, you can define how your data should look, like making a
blueprint for your documents. It's like saying, "In our database, each
person's information will have a name, age, and email." This makes sure
your data stays organized.
● Mongoose helps you make sure the data you put into the database is
correct. It's like having someone check if you've written your email address
correctly before sending a message.
● Very easy to query from the database

—> But if you are using mongodb Native Driver


● You need to write a lot of detailed instructions to make sure everything
works correctly.
● Without Mongoose, your code might get messy and harder to understand.
● Since you need to handle many details yourself, it can take longer to finish
your project.

In a nutshell, using Mongoose makes working with MongoDB in Node.js much


simpler and smoother. It gives you tools that handle complexities for you, so you
can focus on building your application without getting bogged down in technical
details.
DAY 5

● Database Connection

● Connect MongoDB with NodeJS

● CREATE A FILE db.js IN THE ROOT FOLDER

● The db.js file you've created is essentially responsible for establishing a


connection between your Node.js application and your MongoDB database
using the Mongoose library.

● In the Last Lecture, we saw that the mongoose is responsible for


connection
● So let’s import Mongoose Library

● Connection Step by Step

1. Import Mongoose and Define the MongoDB URL: In the db.js file, you
first import the Mongoose library and define the URL to your MongoDB
database. This URL typically follows the format
mongodb://<hostname>:<port>/<databaseName>. In your code,
you've set the URL to 'mongodb://localhost:27017/mydatabase',
where mydatabase is the name of your MongoDB database.
2. Set Up the MongoDB Connection: Next, you call mongoose.connect()
to establish a connection to the MongoDB database using the URL and
some configuration options (useNewUrlParser, useUnifiedTopology,
etc.). This step initializes the connection process but does not actually
connect at this point.
3. Access the Default Connection Object: Mongoose maintains a default
connection object representing the MongoDB connection. You retrieve this
object using mongoose.connection, and you've stored it in the variable
db. This object is what you'll use to handle events and interact with the
database.
4. Define Event Listeners: You define event listeners for the database
connection using methods like .on('connected', ...),
.on('error', ...), and .on('disconnected', ...). These event
listeners allow you to react to different states of the database connection.
5. Start Listening for Events: The code is set up to listen for events. When
you call mongoose.connect(), Mongoose starts the connection process.
If the connection is successful, the 'connected' event is triggered, and
you log a message indicating that you're connected to MongoDB. If there's
an error during the connection process, the 'error' event is triggered,
and you log an error message. Similarly, the 'disconnected' event can
be useful for handling situations where the connection is lost.
6. Export the Database Connection: Finally, you export the db object, which
represents the MongoDB connection, so that you can import and use it in
other parts of your Node.js application.

To sum it up, the db.js file acts as a central module that manages the
connection to your MongoDB database using Mongoose. It sets up the
connection, handles connection events, and exports the connection object so
that your Express.js server (or other parts of your application) can use it to
interact with the database. When your server runs, it typically requires or
imports this db.js file to establish the database connection before
handling HTTP requests.

● What are models or schema?

● Models are like a blueprint of our database


● It’s a representation of a specific collection in MongoDB. Like a Person
● Once you have defined a model, you can create, read, update, and delete
documents in the corresponding MongoDB collection.
● Mongoose allows you to define a schema for your documents. A schema is
like a blueprint that defines the structure and data types of your documents
within a collection.
● Each Person's Detail ( like chef, owner, manager, waiter )

{
"name": "Alice",
"age": 28,
"work": "Chef",
"mobile": "123-456-7890",
"email": "[email protected]",
"address": "123 Main St, City",
"salary": 60000
}

https://mongoosejs.com/docs/guide.html

● Parameters:
● Type, required, unique, etc

● What is body-parser

● bodyParser is a middleware library for Express.js.


● It is used to parse and extract the body of incoming HTTP requests.

● When a client (e.g., a web browser or a mobile app) sends data to a server,
it typically includes that data in the body of an HTTP request.
● This data can be in various formats, such as JSON, form data, or
URL-encoded data. bodyParser helps parse and extract this data from
the request so that you can work with it in your Express.js application.
● bodyParser processes the request body before it reaches your route
handlers, making the parsed data available in the req.body for further
processing.
● bodyParser.json() automatically parses the JSON data from the
request body and converts it into a JavaScript object, which is then stored
in the req.body

● Express.js uses lots of middleware and to use middleware we use the


app.use()
const bodyParser = require('body-parser');
app.use(bodyParser.json());

● Send Data from Client to Server

● we need an Endpoint where the client sends data and data needs to be
saved in the database
● we need a method called POST
● Now code the POST method to add the person
● If we send the random values as well Mongoose will not save random
values other than predefined schema

newPerson.save((error, savedPerson) => {


if (error) {
console.error('Error saving person:', error);
res.status(500).json({ error: 'Internal server error' });
} else {
console.log('Data saved');
res.status(201).json(savedPerson);
}
});

● Async and Await

● Nowadays no one uses callback functions like, we used in the POST


methods They look quite complex and also do not give us code readability.
● What actually callback does, callback is a function that is executed just after
the execution of another main function, it means the callback will wait until
its main function is not executed

● Async and await are features in JavaScript that make it easier to work with
asynchronous code, such as network requests, file system operations, or
database queries.
● Using try-and-catch block
● The try block contains the code for creating a new Person document and
saving it to the database using await newPerson.save().
● If an error occurs during any step, it is caught in the catch block, and an
error response is sent with a 500 Internal Server Error status.
app.post('/person', async (req, res) => {
try {
const newPersonData = req.body;
const newPerson = new Person(newPersonData);

// Save the new person to the database using await


const savedPerson = await newPerson.save();

console.log('Saved person to database');


res.status(201).json(savedPerson);
} catch (error) {
console.error('Error saving person:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

● Async Function (async):


○ An async function is a function that is designed to work with
asynchronous operations. You declare a function as async by placing
the async keyword before the function declaration.
○ The primary purpose of an async function is to allow you to use the
await keyword inside it, which simplifies working with promises and
asynchronous code.
○ Inside an async function, you can use await to pause the execution
of the function until a promise is resolved. This makes the code
appear more synchronous and easier to read.
● Await (await):
○ The await keyword is used inside an async function to wait for the
resolution of a promise. It can only be used within an async function.
○ When await is used, the function pauses at that line until the promise
is resolved or rejected. This allows you to write code that appears
sequential, even though it's performing asynchronous tasks.
○ If the promise is resolved, the result of the promise is returned. If the
promise is rejected, it throws an error that can be caught using
try...catch.

● CRUD application

● In any application at the core level, we are always handling the database

● Now we have seen that two methods POST and GET


● GET Methods

● Now Let’s suppose the client wants data on all the persons
● So we need an endpoint for that /person

app.get('/person', async (req, res) => {


try {
// Use the Mongoose model to fetch all persons from the
database
const persons = await Person.find();

// Send the list of persons as a JSON response


res.json(persons);
} catch (error) {
console.error('Error fetching persons:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

● Create schema for Menu

● Now create a model for the menu

const mongoose = require('mongoose');

const menuItemSchema = new mongoose.Schema({


name: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
taste: {
type: String,
enum: ['Sweet', 'Spicy', 'Sour'],
},
is_drink: {
type: Boolean,
default: false,
},
ingredients: {
type: [String],
default: [],
},
num_sales: {
type: Number,
default: 0,
}
});

const MenuItem = mongoose.model('MenuItem', menuItemSchema);

module.exports = MenuItem;
DAY 6

● Homework Update for Menu API

● Task To create POST /menu and GET /menu

● We are now creating a POST method to save menu details and it’s similar
to person details and the same for the GET method

● Flow Diagram of API

https://drive.google.com/file/d/1TswAyCgfsa04Hp6f4OP-Umg_GVkdW4eQ/view?
usp=sharing

● Parametrised API calls

● Now if someone told you to give a list of people who are only waiters
● Then we can create an endpoint like this
● /person/chef
● /person/waiter
● /person/manager

● But this is not the correct method to create as many functions Here we can
use parametrized endpoints
● It can be dynamically inserted into the URL when making a request to the
API.

● localhost:3000/person/:work

→ work = [ “chef”, “waiter”, “manager” ]

app.get('/person/:work', async (req, res) => {


try {
const workType = req.params.work; // Extract the work type
from the URL parameter

// Assuming you already have a Person model and MongoDB


connection set up
const persons = await Person.find({ work: workType });

// Send the list of persons with the specified work type as


a JSON response
res.json(persons);
} catch (error) {
console.error('Error fetching persons:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
● Express Router

● We have lots of Endpoints in a single file server.js


● This makes bad experience in code readability as well as code handling
● Express Router is a way to modularize and organize your route handling
code in an Express.js application.
● So let’s create a separate file to manage endpoints /person and /menu
● Express Router is like a traffic cop for your web server
● Express Router helps you organize and manage these pages or endpoints
in your web application. It's like creating separate folders for different types
of tasks.

● Create a folder routes → personRoutes.js


const express = require('express');
const router = express.Router();

// Define routes for /person


router.get('/', (req, res) => {
// Handle GET /person
});

router.post('/', (req, res) => {


// Handle POST /person
});

module.exports = router;
● Now in server.js, we will use this personRoutes
// Import the router files
const personRoutes = require('./routes/personRoutes');

// Use the routers


app.use('/person', personRoutes);

● Update Operation

● We will update our person Records, and for that, we will create an endpoint
from where we are able to update the record
● For Updation, we need two things
○ Which record we want to update?
○ What exactly do we want to update?
● For update, we will use the PUT method to create an endpoint
● What is a unique identifier in a document in a collection?
● It’s _id which Mongodb itself gives, We will use this to find the particular
record that we want to update
● —> And now we will send the data the same as we did in the POST
method.

app.put('/person/:id', async (req, res) => {


try {
const personId = req.params.id; // Extract the person's ID
from the URL parameter
const updatedPersonData = req.body; // Updated data for the
person

// Assuming you have a Person model


const updatedPerson = await
Person.findByIdAndUpdate(personId, updatedPersonData, {
new: true, // Return the updated document
runValidators: true, // Run Mongoose validation
});

if (!updatedPerson) {
return res.status(404).json({ error: 'Person not found'
});
}

// Send the updated person data as a JSON response


res.json(updatedPerson);
} catch (error) {
console.error('Error updating person:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

● Delete Operation

● We will Delete our person Records, and for that we will create an endpoint
from where we are able to delete the record
● For Deletion, we need one thing
○ Which record we want to update?
● For deletion, we will use the DELETE method to create an endpoint
● What is a unique identifier in a document in a collection?
● It’s _id which Mongodb itself gives, We will use this to find the particular
record that we want to delete

app.delete('/person/:id', async (req, res) => {


try {
const personId = req.params.id; // Extract the person's ID
from the URL parameter

// Assuming you have a Person model


const deletedPerson = await Person.findByIdAndRemove(personId);

if (!deletedPerson) {
return res.status(404).json({ error: 'Person not found' });
}

// Send a success message as a JSON response


res.json({ message: 'Person deleted successfully' });
} catch (error) {
console.error('Error deleting person:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
DAY 7

● Git & GitHub

● Git is like a time machine for your code.

● It is a tool that keeps a record of every version of your code, so you can
always go back to a previous state if something goes wrong.

● Install Git: If you haven't already, download and install Git on your
computer. You can get it from the official Git website:
https://git-scm.com/downloads
● If you want to work with git in your project →
● Run git init inside the root folder of your project
● This command tells Git to start tracking changes in your project folder.

git status

● After making changes to your project (e.g., writing code), you'll want to save
those changes in Git.
git add .
● The . means "add all changes." You can replace it with specific file names
if needed.

● gitignore

● The .gitignore file is a special configuration file used in Git repositories


to specify files and directories that Git should ignore.
● These ignored files and directories won't be tracked by Git or included in
version control.
● Create .gitignore File
# Ignore node_modules directory
node_modules/

# Other entries...

● This saves a snapshot of your project's current state.

git commit -m "Initial commit"

● If you want to collaborate with others or back up your code online, you can
create a remote repository on platforms like GitHub

● Link Your Local and Remote Repositories


● If you created a remote repository, you can link it to your local one

git remote add origin https://github.com/yourusername/hotels.git

● Push Changes to Remote


● To send your local commits to the remote repository, use the git push
command
git push -u origin master

● Pull Changes
● If you're collaborating with others, you can fetch their changes and merge
them into your code using git pull.
● Host MongoDB database

● Now we are running locally MongoDB database.


● All data operation is performed in a local database, so let’s host our
database server and make our DB online presence

● MongoDB Atlas provides a Free cluster for users where you can host your
database for free.
● MongoDB Atlas offers a cloud-based platform for hosting MongoDB
databases
● The free tier allows developers to explore and experiment with the database
without incurring any costs.
● https://www.mongodb.com/atlas/database

● Create an account for free ( I already have an account )


● Show Step-by-step Process to host MongoDB Atlas

● Dotenv

● The dotenv module in Node.js is used to manage configuration variables


and sensitive information in your applications.
● It's particularly useful for keeping sensitive data like API keys, database
connection strings, and other environment-specific configurations separate
from your code.
npm install dotenv
● Create a .env File
● This is where you'll store your environment-specific configuration variables.
● format VAR_NAME=value.
PORT=3000
API_KEY=your-api-key
DB_CONNECTION_STRING=your-db-connection-string

● In your server file (usually the main entry point of your application), require
and configure the dotenv module.

require('dotenv').config();

● Access Configuration Variables:

const port = process.env.PORT || 3000; // Use 3000 as a default


if PORT is not defined
const apiKey = process.env.API_KEY;
const dbConnectionString = process.env.DB_CONNECTION_STRING;

● Remember to keep your .env file secure and never commit it to a public
version control system like Git, as it may contain sensitive information.
Typically, you should include the .env file in your project's .gitignore file
to prevent accidental commits.

● Test MongoDB Cluster Postman

● Now we can test the MongoDB Cluster and check whether our data is
present or not in the online DB

● Host NodeJS Server

● Now we are going to host our server so that our Application or Endpoints is
accessible to all the users over the Internet.
● We are using localhost and our endpoints are only accessible within our
computer
● We have to make it publicly available, so there are lots of company who
helps us to make our application run 24*7
● Like, AWS, Google Cloud, etc. but these charge too much amount for our
application
● So we are going to use some free services to host our nodeJS application,
which lots of company provides for developer purposes.
● Like, Heroku, Netlify, Render, etc
DAY 8

●​ Middleware

Imagine you're at a restaurant, and you've placed an order for your favorite dish. Now,
before that dish reaches your table, it goes through several stages in the kitchen. Each
stage involves different tasks, like chopping vegetables, cooking, and adding spices.
Middleware is a bit like these stages in the kitchen—it's something that happens in
between your request and the final response in a web application.

Now, let's apply this idea to a web application, like the "Node Hotel" system:

1.​ Request Phase:


○​ You (the client) make a request to the Node Hotel system. It could be
asking for the menu, submitting a reservation, or anything else.
2.​ Middleware Phase:
○​ Middleware is like the behind-the-scenes process in the kitchen. It's a
series of functions that your request goes through before it reaches the
final destination.
3.​ Final Response Phase:
○​ After passing through the middleware, your request gets processed, and
the system sends back a response. It could be the menu you requested or
confirmation of your reservation.
Example in Node.js:

In the context of Node.js, imagine you want to log every request made to your "Node
Hotel" application. You could use middleware for this.

// Middleware Function​
const logRequest = (req, res, next) => {​
console.log(`[${new Date().toLocaleString()}] Request made to:
${req.originalUrl}`);​
next(); // Move on to the next phase​
};​

// Using Middleware in Express​
const express = require('express');​
const app = express();​

// Apply Middleware to all Routes​
app.use(logRequest);​

// Define Routes​
app.get('/', (req, res) => {​
res.send('Welcome to Node Hotel!');​
});​

app.get('/menu', (req, res) => {​
res.send('Our delicious menu is coming right up!');​
});​

// Start the Server​
const PORT = 3000;​
app.listen(PORT, () => {​
console.log(`Server is running on http://localhost:${PORT}`);​
});
In this example, logRequest is our middleware. It logs the time and the requested
URL for every incoming request. The app.use(logRequest) line tells Express to
use this middleware for all routes.

So, when you access any route (like / or /menu), the middleware runs first, logs the
request, and then the route-specific code executes.

In summary, middleware is like a series of tasks that happen behind the scenes in a
web application. It's a way to add extra functionality to your application's
request-response cycle, such as logging, authentication checks, or modifying
request data, before it reaches its final destination.

Why do we use the next() function in the middleware function

In Express.js, the next() function is a callback that signals to Express that the current
middleware function has completed its processing and that it's time to move on to the
next middleware function or route handler in the chain.


●​ Authentication & Authorization

Like Aim: 700


Comment Aim: 400
Please Like this Video Before watching

Tag me on Linkedin for Notes – show Demo How you can post
Imagine you're the manager of the "Node Hotel" application, and you want to ensure
that only authorized staff members can access certain features. This is where
authentication comes in.

1. Verifying Identity (Authentication):

●​ Scenario: When a staff member, let's say a chef, wants to log in to the Node
Hotel system, they need to prove that they are indeed the chef they claim to be.
●​ In Practice: In Node.js, authentication involves checking the chef's credentials,
like a username and password, to make sure they match what's on record. It's
like asking the chef to enter a secret code (password) and confirming that it's
correct.

2. Access Control (Authorization):

Now, let's add a layer of authorization based on the roles of the staff members.

●​ Scenario: Once the chef has proven their identity, you, as the manager, want to
control what they can and cannot do. For instance, chefs should be able to
update the menu items, but maybe not manage staff salaries.
●​ In Practice: In Node.js, after authenticating the chef, you'll use authorization to
decide what parts of the system they have access to. It's like giving the chef a
key card (authorization) that lets them into the kitchen but not into the manager's
office.

Implementation in Node.js:

1.​ Authentication Middleware:


○​ In your Node.js application, you might use middleware like Passport to
handle the authentication process.
○​ Passport helps verify the identity of the chef based on their provided
credentials.
2.​ User Roles and Permissions:
○​ You'll define roles for staff members (e.g., chef, waiter, manager).
○​ Authorization middleware will check the role of the authenticated user and
grant access accordingly.
3.​ Secure Endpoints:
○​ You'll protect certain routes (like updating menu items) with authentication
checks.
○​ Only authenticated and authorized users (like chefs) will be allowed to
access these routes.

In the Hotel Context:

●​ Authentication: When Chef John logs in, the system checks if the provided
username and password match what's on record for Chef John.
●​ Authorization: Once authenticated, Chef John is authorized to modify menu
items but may not have permission to change other critical settings.

In simple terms, authentication in Node.js for your hotel application ensures that each
staff member is who they say they are, and authorization determines what they're
allowed to do once their identity is confirmed.

It's like having a secure system where only the right people get access to the right
areas of your hotel management application.

In general, authentication is applied before authorization in the security process. Here's


the typical sequence:

1.​ Authentication:
○​ The first step is to verify the identity of the user or system entity attempting
to access a resource or perform an action. This involves checking
credentials such as usernames and passwords or using other
authentication methods like tokens, API keys, or certificates.
2.​ Authorization:
○​ Once the identity is verified through authentication, the system moves on to
authorization. Authorization determines what actions or resources the
authenticated user or entity is allowed to access based on their
permissions, roles, or other access control mechanisms.

The reason for this order is straightforward: before you can determine what someone is
allowed to do (authorization), you need to know who they are (authentication).
Authentication establishes the identity, and authorization defines the permissions
associated with that identity.
In the context of web applications, middleware for authentication is typically applied
first in the request-response cycle to verify the user's identity. If authentication is
successful, the request proceeds to authorization middleware to determine what the
authenticated user is allowed to do.

It's important to note that while authentication and authorization are often discussed as
distinct steps, they work together as essential components of a security strategy to
control access to resources and protect against unauthorized actions.

●​ Now we will implement Authentication as a middleware Function. So that, Routes


will be authenticated before reaching out to the server.
●​ Implementing authentication as a middleware function is a common and effective
approach.

●​ Passport.js

Passport.js is a popular authentication middleware for Node.js. Authentication is the


process of verifying the identity of a user, typically through a username and password,
before granting access to certain resources or features on a website or application.

Think of Passport.js as a helpful tool that makes it easier for developers to handle user
authentication in their Node.js applications. It simplifies the process of authenticating
users by providing a set of pre-built strategies for different authentication methods,
such as username and password, social media logins (like Facebook or Google), and
more.

Here's a breakdown of some key concepts in Passport.js:

1.​ Middleware: In the context of web development, middleware is software that sits
between the application and the server. Passport.js acts as middleware,
intercepting requests and adding authentication-related functionality to them.
2.​ Strategy: Passport.js uses the concept of strategies for handling different
authentication methods. A strategy is a way of authenticating users. Passport.js
comes with various built-in strategies, and you can also create custom strategies
to support specific authentication providers.
3.​ Serialize and Deserialize: Passport.js provides methods for serializing and
deserializing user data. Serialization is the process of converting user data into a
format that can be stored, usually as a unique identifier. Deserialization is the
reverse process of converting that unique identifier back into user data. These
processes are essential for managing user sessions.
●​ Install Passport

To use Passport.js in a Node.js application, you need to install the passport package
along with the authentication strategies you intend to use.

For this course, we are using Local strategies authentication (username and
password).

you would typically install passport-local

npm install passport passport-local

Once you've installed these packages, you can set up and configure Passport.js in
your application.

const express = require('express');​


const passport = require('passport');​
const LocalStrategy = require('passport-local').Strategy;​
const app = express();​
// Initialize Passport​
app.use(passport.initialize());

●​ Passport Local Strategy

●​ The Passport Local Strategy is a part of the Passport.js authentication


middleware for Node.js. It's specifically designed for handling username and
password-based authentication.
●​ The Passport Local Strategy, by default, expects to extract the username and
password from the request body. It is a common practice for username and
password-based authentication systems to send the credentials as part of the
request body, especially in login forms.
●​ Add username & password

●​ Now we have to add username and password in the person schema

●​ Configure the Local Strategy

●​ Define and configure the Local Strategy using passport-local.


●​ You need to provide a verification function that checks the provided username
and password.

passport.use(new LocalStrategy(​
async (username, password, done) => {​
// Your authentication logic here​
}​
));

●​ In the Local Strategy's verification function, you typically query your database to
find the user with the provided username. You then compare the provided
password with the stored password.
●​ In the context of LocalStrategy, Passport.js expects the verification function
to have the following signature:
function(username, password, done)

●​ The done callback should always be the last parameter, and it's essential to
maintain this order for Passport.js to work correctly. If you change the order of
parameters, you risk breaking the expected behavior of Passport.js.

passport.use(new LocalStrategy(async (username, password, done) => {​


try {​
console.log('Received credentials:', username, password);​
const user = await Person.findOne({ username });​
if (!user)​
return done(null, false, { message: 'Incorrect username.' });​

const isPasswordMatch = (user.password === password ? true : false);​
if (isPasswordMatch)​
return done(null, user);​
else​
return done(null, false, { message: 'Incorrect password.' })​
} catch (error) {​
return done(error);​
}​
}));

●​ In the context of Passport.js, done is a callback function that is provided by


Passport to signal the completion of an authentication attempt. It is used to
indicate whether the authentication was successful, and if so, to provide
information about the authenticated user.
●​ The done function takes three parameters: done(error, user, info).
●​ If the authentication is successful, you call done(null, user) where user is
an object representing the authenticated user.
●​ If the authentication fails, you call done(null, false, { message: 'some
message' }). The second parameter (false) indicates that authentication
failed, and the third parameter is an optional info object that can be used to
provide additional details about the failure.
●​ Passport Authenticate

●​ Once you have configured Passport Local Strategy, the next steps typically
involve integrating it into your application.
●​ In route, we should use passport.authenticate() to initiate the
authentication process.
●​ To authenticate any routes, we need to pass this as an middleware

Let’s suppose we want to Authenticate this Route

app.get('/', function (req, res) {​


res.send('Welcome to our Hotel');​
})

●​ We have to initialize the passport

app.use(passport.initialize());​
app.get('/', passport.authenticate('local', { session: false }), function (req, res) {​
res.send('Welcome to our Hotel');​
})

Or we can also write like this

app.use(passport.initialize());​
const localAuthMiddleware = passport.authenticate('local', { session: false });​

app.get('/', localAuthMiddleware, function (req, res) {​
res.send('Welcome to our Hotel');​
})
●​ Now, we can test the ‘ / ‘routes it needs parameter

●​ Same way, we can also pass authenticate /person routes.

●​ Passport Separate File

●​ Now, rather than all the passport codes in a server file. We can separate it into
another file name auth.js
●​ And in the server.js file, we will import the passport
// sets up Passport with a local authentication strategy, using a Person model
for user data. - Auth.js file​

const passport = require('passport');​
const LocalStrategy = require('passport-local').Strategy;​
const Person = require('./models/Person'); // Adjust the path as needed​

passport.use(new LocalStrategy(async (username, password, done) => {​
try {​
console.log('Received credentials:', username, password);​
const user = await Person.findOne({ username });​
if (!user)​
return done(null, false, { message: 'Incorrect username.' });​

const isPasswordMatch = user.password === password ? true : false;​
if (isPasswordMatch)​
return done(null, user);​
else​
return done(null, false, { message: 'Incorrect password.' })​
} catch (error) {​
return done(error);​
}​
}));​

module.exports = passport; // Export configured passport
●​ Store Plain Password

●​ Storing plain passwords is not a secure practice. To enhance security, it's highly
recommended to hash and salt passwords before storing them.

●​ You can use the bcrypt library for password hashing in your Node.js
application.

npm install bcrypt


●​ bcrypt.js

●​ Now we have to update our person model to store hashed passwords. Modify the
registration logic to hash the password before saving it to the database.
●​ Because the end user didn’t know about hashing, we have to internally maintain
it. Like we are saving the hashed password before saving it into the database
●​ We are using a Mongoose middleware hook to perform an action before saving a
document to the database. Specifically, it's using the pre middleware to execute
a function before the save operation.
personSchema.pre('save', async function(next) {​
const person = this;​

// Hash the password only if it has been modified (or is new)​
if (!person.isModified('password')) return next();​

try {​
// Generate a salt​
const salt = await bcrypt.genSalt(10);​

// Hash the password with the salt​
const hashedPassword = await bcrypt.hash(person.password, salt);​

// Override the plain password with the hashed one​
person.password = hashedPassword;​
next();​
} catch (error) {​
return next(error);​
}​
});

●​ The pre('save', ...) middleware is triggered before the save operation on


a Mongoose model instance.
●​ Inside the middleware function, it checks if the password field has been modified
(or if it's a new document). If not, it skips the hashing process.
●​ If the password has been modified, it generates a new salt using
bcrypt.genSalt and then hashes the password using bcrypt.hash.
●​ The original plain text password in the person document is then replaced with
the hashed password.
●​ The next() function is called to proceed with the save operation.

●​ The line const salt = await bcrypt.genSalt(10); is responsible for


generating a salt, which is a random string of characters used as an additional
input to the password hashing function. Salting is a crucial step in password
hashing to prevent attackers from using precomputed tables (rainbow tables) to
quickly look up the hash value of a password.
●​ bcrypt.genSalt(rounds): This function generates a salt using the specified
number of "rounds." The rounds parameter indicates the complexity of the
hashing algorithm. The higher the number of rounds, the more secure the salt,
but it also increases the computational cost.

if (!person.isModified('password')) return next();

This line is a conditional check that prevents unnecessary rehashing of the password
when the document is being saved.

●​ person.isModified('password'): This method is provided by Mongoose


and returns true if the specified field ('password' in this case) has been
modified. It returns false if the field hasn't been modified.
●​ return next();: If the password field has not been modified, the function
immediately returns, skipping the rest of the middleware. This is because there's
no need to rehash the password if it hasn't changed.

●​ How bcrypt works

When you use bcrypt to hash a password, the library internally stores the salt as part
of the resulting hashed password. This means that you don't need to separately store
the salt in your database; it is included in the hashed password itself.

Here's a simplified explanation of how it works:

1.​ Hashing a Password:

When you hash a password using bcrypt.hash, the library generates a random salt,
hashes the password along with the salt, and produces a hashed password that
incorporates both the salt and the hashed value.

const salt = await bcrypt.genSalt(10);​


const hashedPassword = await bcrypt.hash('userPassword', salt);

The hashedPassword now contains both the hashed password and the salt.
●​ Modify Auth code

We have to also modify the password-matching logic in the passport auth file.

●​ Let’s create a comparePassword named function which compares or check the


password.

●​ Compare function

We also have to write the compare function

// Define the comparePassword method​


personSchema.methods.comparePassword = async function(candidatePassword) {​
try {​
// Use bcrypt to compare the provided password with the hashed password​
const isMatch = await bcrypt.compare(candidatePassword, this.password);​
return isMatch;​
} catch (error) {​
throw error;​
}​
};
Verifying a Password

When you later want to verify a user's entered password during login, you use
bcrypt.compare. This function internally extracts the salt from the stored hashed
password and uses it to hash the entered password for comparison.

const isMatch = await bcrypt.compare('enteredPassword', storedHashedPassword);

The compare function automatically extracts the salt from storedHashedPassword


and uses it to hash the entered password. It then compares the resulting hash with the
stored hash. If they match, it indicates that the entered password is correct.
DAY 9

Sessions or Tokens

Sessions are a way to maintain user state and authenticate users in web applications.

1. User Authentication

When you visit a website or use a web application, you must log in to access certain
features or personalized content. Sessions or tokens are used to authenticate users,
proving that they are who they claim to be. This ensures that only authorized users can
access restricted areas or perform certain actions.

2. Maintaining User State

Web applications often need to remember user information as they navigate through
different pages or interact with the app. Sessions or tokens help maintain this user
state. For example, if you add items to your shopping cart on an e-commerce website,
the website needs to remember those items as you browse other pages. Sessions or
tokens store this information so that it can be accessed later.

3. Security

Sessions and tokens play a crucial role in securing web applications. They help
prevent unauthorized access by verifying the identity of users before granting them
access to sensitive data or functionality. Additionally, they can be used to protect
against common security threats such as session hijacking or cross-site request
forgery (CSRF) attacks.

4. Personalization and Customization

Sessions or tokens allow web applications to provide personalized experiences to


users. By storing information about users' preferences, settings, or past interactions,
the application can tailor the content or functionality to better meet their needs. This
enhances user satisfaction and engagement with the application.

5. Scalability

Sessions and tokens are designed to scale with the size and complexity of web
applications. They provide a flexible and efficient way to manage user authentication
and state, even as the number of users or requests increases. This scalability is
essential for ensuring that web applications can handle growing traffic and user
demands without sacrificing performance.
In summary, sessions and tokens are essential components of web development,
enabling user authentication, maintaining state, ensuring security, personalizing
experiences, and supporting scalability. They form the foundation of secure and
user-friendly web applications that can provide personalized and seamless
experiences to users.

Sessions based Authentication

●​ A session is a way or a small file, most likely in JSON format, that stores
information about the user, such as a unique ID, time of login expirations, and so
on. It is generated and stored on the server so that the server can keep track of
the user requests.

Working

1.​ The user sends a login request to the server.


2.​ The server authenticates the login request, sends a session to the database, and
returns a cookie containing the session ID to the user.
3.​ Now, the user sends new requests (with a cookie).
4.​ The server checks in the database for the ID found in the cookie, if the ID is
found it sends the requested pages to the user.
Cookies

A cookie is a small piece of data that a website stores on a user's computer or


device. Cookies are commonly used by websites to remember information about the
user's browsing activity, preferences, and interactions with the site. Here's a
beginner-friendly explanation of cookies
How Cookies Work

●​ Creation: When you visit a website for the first time, the website may send a
small text file (the cookie) to your browser.
●​ Storage: Your browser stores the cookie on your computer or device. Each
cookie is associated with a specific website and contains information such as a
unique identifier and any data the website wants to remember about you.
●​ Sending with Requests: When you revisit the website or navigate to different
pages on the same site, your browser automatically includes the cookie in the
HTTP requests it sends to the website's server.
●​ Server Processing: The website's server receives the cookie along with the
request. It can then read the cookie to retrieve the stored information about you.
●​ Usage: Websites use cookies for various purposes, such as remembering your
login status, storing your preferences, tracking your activities for analytics
purposes, and personalizing your browsing experience.

Types of Cookies

●​ Session Cookies: These cookies are temporary and are deleted when you close
your browser. They are often used for maintaining your login state during a
browsing session.
●​ Persistent Cookies: These cookies are stored on your device for a specified
duration, even after you close your browser. They can be used for purposes such
as remembering your preferences or login information across multiple visits to a
website.
Privacy and Security

Cookies can raise privacy concerns because they can be used to track users' browsing
behavior across different websites. However, cookies cannot execute code or transmit
viruses, and they can only store information that the website itself provides.
In summary, cookies are small text files stored on your computer by websites you
visit. They help websites remember information about you and enhance your browsing
experience by personalizing content, maintaining login status, and tracking
preferences. While cookies are an essential part of web functionality, they also raise
privacy considerations, and users can manage their cookie settings in their web
browsers.

Client Storage option

It's not mandatory that the cookies received from the server will be stored in the
"Cookies" storage of your browser. The browser provides multiple storage options,
each serving different purposes and offering various capabilities:

1.​ Cookies Storage: Cookies received from the server are typically stored in the
"Cookies" storage of your browser. These cookies can include session cookies,
which are deleted when you close your browser, and persistent cookies, which
are stored for a longer period.
2.​ Local Storage: Local storage is a mechanism that allows web applications to
store data locally in the browser. Unlike cookies, data stored in local storage is
not automatically sent to the server with every request. This storage option is
often used for caching data, storing user preferences, or implementing client-side
features.
3.​ Session Storage: Session storage is similar to local storage but is scoped to a
particular browsing session. Data stored in session storage is cleared when you
close the browser or tab. It's commonly used for temporary data storage or for
maintaining a state within a single browsing session.

Important Points

●​ While cookies are commonly used for storing session identifiers ( session IDs) or
authentication tokens received from the server, web applications can choose to
store this information in local storage or session storage instead.
●​ The choice of storage mechanism depends on factors such as security
requirements, application architecture, and use case. Cookies offer automatic
inclusion in HTTP requests and can be more secure if configured properly, but
local storage and session storage provide more control over data management
on the client side.
●​ While cookies are a common way to store data received from the server, web
applications have the flexibility to choose other storage options such as local
storage or session storage based on their requirements.

Token based Authentication

●​ A token is an authorization file that cannot be tampered with. It is generated by


the server using a secret key, sent to and stored by the user in their local storage.
Like in the case of cookies, the user sends this token to the server with every
new request, so that the server can verify its signature and authorize the
requests.

●​ Working

●​ The user sends a login request to the server.


●​ The server authorizes the login and sends a token to the user.
●​ Now, the user sends a new request(with a token).
●​ The server checks whether the token is valid or not, if the token is valid it sends
the requested pages to the user.

Note- Those are not authentication files, they are authorization ones. While
receiving a token, the server does not look up who the user is, it simply authorizes the
user’s requests relying on the validity of the token.
Difference between Session & Token

Criteria Token-based
Session authentication method authentication method

1 Which side of the connection Server User


stores the authentication details

2 What the user sends to the server A cookie The token itself
to have their requests authorized

3 What does the server do to Looking up in its databases to find Decrypting the user’s token
authorize users’ requests the right session thanks to the ID and verifying its signature
the user sends with a cookie

4 Can the server admins perform Yes, because the session is stored No, because the token is
securities operations like logging on the server stored on the user’s
users out, changing their details, machine
etc
How Session works
How Token works
DAY 10

As we know tokens are generic authentication credentials or authorization tokens used


to authenticate users or authorize access to resources in web applications.

Tokens refer to a broad category of authentication credentials, whereas JWT is a


specific format or implementation of tokens.

JWT ( JSON Web Token )

●​ Definition: JWT is a specific type of token format defined by the JSON Web
Token standard (RFC 7519). It is a compact and self-contained means of
transmitting information between parties as a JSON object.
●​ Structure: JWTs consist of three parts: header, payload, and signature. They are
typically encoded and signed using cryptographic algorithms.
●​ Usage: JWTs are commonly used for authentication and authorization in web
applications and APIs. They can store user claims, such as user ID, roles,
permissions, and custom data, in a secure and portable format.
●​ Statelessness: JWTs are stateless, meaning the server does not need to store
session information. This makes them suitable for distributed architectures and
scalable systems.
JWT Structure

A JWT is composed of three sections separated by dots (.), following the format
header.payload.signature.

1.​ Header: Contains metadata about the type of token and the cryptographic
algorithms used to secure it. It typically consists of two parts:
○​ Typ (Type): Specifies the type of token, usually set to "JWT".
○​ Alg (Algorithm): Indicates the cryptographic algorithm used to sign the
token, such as HMAC SHA256 or RSA.
2.​ Payload: Contains the claims or statements about the subject (user) and any
additional data. It consists of a set of claims that represent assertions about the
user, such as their identity, roles, or permissions. Claims are categorized into
three types:
○​ Reserved Claims: Predefined claims standardized by the JWT
specification, such as iss (issuer), sub (subject), aud (audience), exp
(expiration time), and iat (issued at).
○​ Public Claims: Custom claims defined by the application developer to
convey information about the user.
○​ Private Claims: Custom claims agreed upon by parties that exchange
JWTs, not registered or standardized.
3.​ Signature: Verifies the integrity of the token and ensures that it has not been
tampered with during transmission. It's created by taking the encoded header,
encoded payload, a secret (for HMAC algorithms), and applying the specified
algorithm to generate the signature.
Authentication Flow
JWT Functions

Certainly! In the context of JSON Web Tokens (JWT), jwt.sign() and


jwt.verify() are two crucial functions provided by the jsonwebtoken library in
Node.js. Here's what they do

jwt.sign():

●​ This function is used to generate a new JWT token based on the provided
payload and options.
●​ It takes three parameters:
○​ payload: This is the data you want to include in the token. It can be any
JSON object containing user information, metadata, or any other relevant
data.
○​ secretOrPrivateKey: This is the secret key used to sign the token. It
can be a string or a buffer containing a secret cryptographic key.
○​ options (optional): These are additional options that control the behavior
of the token generation process, such as expiration time (expiresIn),
algorithm (algorithm), and more.

const jwt = require('jsonwebtoken');​



// Payload containing user information​
const payload = { userId: '123456', username: 'exampleuser' };​

// Secret key for signing the token​
const secretKey = 'your_secret_key';​

// Generate a new JWT token​
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });

jwt.verify():

●​ This function is used to verify and decode a JWT token to retrieve the original
payload.
●​ It takes three parameters:
○​ token: The JWT token to be verified.
○​ secretOrPublicKey: The secret key or public key used to verify the
token's signature. If the token was signed using a symmetric algorithm
(e.g., HMAC), you need to provide the same secret key used to sign the
token. If it was signed using an asymmetric algorithm (e.g., RSA), you need
to provide the public key corresponding to the private key used for signing.
○​ options (optional): Additional options for verification, such as algorithms
(algorithms), audience (audience), issuer (issuer), and more.
// Verify and decode the JWT token​
jwt.verify(token, secretKey, (err, decoded) => {​
if (err) {​
// Token verification failed​
console.error('Token verification failed:', err.message);​
} else {​
// Token verification successful​
console.log('Decoded token:', decoded);​
}​
});

Our Hotel App Flow

For the First Time, User is completely new to the site

1.​ Signup Route (/signup): This route will handle user registration and issue a
JWT token upon successful registration.
2.​ Login Route (/login): This route will handle user login and issue a new JWT
token upon successful authentication.
3.​ Protected Routes: These routes will be accessed only by providing a valid JWT
token.
Install JWT

First, you'll need to install the necessary packages for working with JWT. In Node.js,
you can use packages like jsonwebtoken to generate and verify JWTs.

npm install jsonwebtoken


jwtAuthMiddleware

Create a JWT Auth Middleware function, which is responsible for authentication via
Tokens

// jwtAuthMiddleware.js​
const jwt = require('jsonwebtoken');​

const jwtAuthMiddleware = (req, res, next) => {​
// Extract the JWT token from the request header​
const token = req.headers.authorization.split(' ')[1];​
if (!token) return res.status(401).json({ error: 'Unauthorized' });​

try {​
// Verify the JWT token​
const decoded = jwt.verify(token, process.env.JWT_SECRET);​
// Attach user information to the request object​
req.user = decoded;​
next();​
} catch (err) {​
console.error(err);​
res.status(401).json({ error: 'Invalid token' });​
}​
};​

module.exports = jwtAuthMiddleware;

●​ We can certainly change the variable name from req.user to


req.EncodedData or any other name you prefer. The choice of variable name
(EncodedData, userData, etc.) is flexible and depends on your application's
conventions or requirements.
●​ The key aspect is to make sure that the decoded user information is attached to
the request object (req) so that it can be easily accessed by other middleware
functions or route handlers.
Once you've attached the decoded user information to req.EncodedData within the
jwtAuthMiddleware, you can access it in further routes or middleware functions in
your application

// Example route using req.EncodedData​


router.get('/profile', jwtAuthMiddleware, (req, res) => {​
// Access the decoded user information from req.EncodedData​
const userData = req.EncodedData;​

// Now you can use userData to access user properties like
username, role, etc.​
res.json({ username: userData.username, role: userData.role });​
});

●​ Now, Let’s create a JWT token to generate functions

// Function to generate JWT token​


const generateToken = (userData) => {​
// Generate a new JWT token using user data​
return jwt.sign({user: userData}, process.env.JWT_SECRET, { expiresIn: '1h'
});​
};​

module.exports = { jwtAuthMiddleware, generateToken };

The expiresIn option of jwt.sign() expects the time to be specified in seconds or


a string describing a time span, such as '2 days' or '10h'.
●​ If you want to make sure, expireIn parameter works properly then you have to
pass the payload as a proper object.
●​ Your payload needs to be an object otherwise it's treated as a string.

Validate JWT in Encoder


Login Route

// Login route​
router.post('/login', async (req, res) => {​
try {​
// Extract username and password from request body​
const { username, password } = req.body;​

// Find the user by username​
const user = await Person.findOne({ username });​

// If user does not exist or password does not match, return error​
if (!user || !(await user.comparePassword(password))) {​
return res.status(401).json({ error: 'Invalid username or
password' });​
}​

const payload = { id: user.id, email: user.email }​

// Generate JWT token​
const token = generateToken(payload);​

// Send token in response​
res.json({ token });​
} catch (err) {​
console.error(err);​
res.status(500).json({ error: 'Internal Server Error' });​
}​
});
Profile Route

router.get('/profile', jwtAuthMiddleware, async (req, res) => {​


try {​
// Extract user id from decoded token​
const userId = req.user.id;​

// Find the user by id​
const user = await Person.findById(userId);​

// If user does not exist, return error​
if (!user) {​
return res.status(404).json({ error: 'User not found' });​
}​

// Send user profile as JSON response​
res.json(user);​
} catch (err) {​
console.error(err);​
res.status(500).json({ error: 'Internal Server Error' });​
}​
});
Important Points:

When the server receives this request, it parses the Authorization header to
extract the JWT token.

const authorizationHeader = 'Bearer


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmF
tZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJ
f36POk6yJV_adQssw5c';​
const token = authorizationHeader.split(' ')[1];​
console.log(token); // Output:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmF
tZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJ
f36POk6yJV_adQssw5c

The split(' ') method separates the header value into an array of substrings using
the space (' ') character as the delimiter. The [1] index accesses the second element
of this array, which is the JWT token.

We can Add one more line of check in the jwtAuthMiddleware

const authHeader = req.headers.authorization;​


if (!authHeader) return res.status(401).json({ error: 'Token required'
});

Expire Time-based Token


DAY - 01

Problems

Problem 1: Conditional Statements (if-else)

You run a movie theater, and you want to offer discounts based on a person's age. Write a
JavaScript program that asks the user for their age and then displays a message:
- If the age is less than 18, display "You get a 20% discount!"
- If the age is between 18 and 65 (inclusive), display "Normal ticket price applies."
- If the age is 65 or older, display "You get a 30% senior discount!"

Problem 2: Variables (var and const)

Create a JavaScript program to calculate the area of a rectangle. Ask the user for the length
and width of the rectangle and store them in variables. Calculate and display the area using
the formula: `area = length * width`.

Problem 3: Objects and Properties

You're creating an online store. Define a JavaScript object named "product" with the following
properties:
- name (string)
- price (number)
- inStock (boolean)

Create at least three products using your object template and display their details using
console.log.

Problem 4: Arrays

You're organizing a party and want to keep track of the guest list. Create an array called
"guestList" and add the names of at least five guests. Then, write a program that checks if a
given name is on the guest list. If the name is found, display "Welcome to the party, [name]!";
otherwise, display "Sorry, you're not on the guest list."
Problem 5: JSON (JavaScript Object Notation)

You're working on a weather app. Create a JSON object representing the weather forecast for
a specific day. Include properties like "date," "temperature," "conditions," and "humidity."
Display the information using console.log.

Remember to encourage your students to experiment and think creatively while solving these
problems. They can use the concepts you've taught them to come up with their own solutions.
This will not only help solidify their understanding but also foster their problem-solving skills in
JavaScript.

Solution

Problem 1: Conditional Statements (if-else)

const age = prompt("Please enter your age:");


if (age < 18) {
console.log("You get a 20% discount!");
} else if (age >= 18 && age <= 65) {
console.log("Normal ticket price applies.");
} else {
console.log("You get a 30% senior discount!");
}

Problem 2: Variables (var and const)

const length = parseFloat(prompt("Enter the length of the rectangle:"));


const width = parseFloat(prompt("Enter the width of the rectangle:"));
const area = length * width;
console.log("The area of the rectangle is:", area);
Problem 3: Objects and Properties

const product1 = {
name: "Smartphone",
price: 399.99,
inStock: true
};

const product2 = {
name: "Laptop",
price: 999.99,
inStock: false
};

const product3 = {
name: "Headphones",
price: 49.99,
inStock: true
};

console.log(product1);
console.log(product2);
console.log(product3);

Problem 4: Arrays

const guestList = ["Alice", "Bob", "Charlie", "David", "Eve"];

const nameToCheck = prompt("Enter your name:");


if (guestList.includes(nameToCheck)) {
console.log(`Welcome to the party, ${nameToCheck}!`);
} else {
console.log("Sorry, you're not on the guest list.");
}
Problem 5: JSON (JavaScript Object Notation)

const weatherForecast = {
date: "2023-08-06",
temperature: 28,
conditions: "Sunny",
humidity: 60
};

console.log("Weather Forecast for", weatherForecast.date);


console.log("Temperature:", weatherForecast.temperature + "°C");
console.log("Conditions:", weatherForecast.conditions);
console.log("Humidity:", weatherForecast.humidity + "%");

DAY - 02

Problems

Problem 1: NPM and Package.json

You're starting a new project and want to manage your project's dependencies using NPM.
Explain the purpose of NPM and how it helps in managing packages. Create a simple
package.json file for your project, specifying the name, version, and a few dependencies of
your choice.

Problem 2: Writing Functions

Write a JavaScript function named calculateCircleArea that takes the radius of a circle
as a parameter and returns the area of the circle. You can use the formula area = π *
radius^2. Test the function with a few different radii.
Problem 3: Callback Functions

Create a function named performOperation that takes two numbers and a callback
function as parameters. The callback function should determine the operation to be performed
(addition, subtraction, multiplication, or division) on the two numbers. Call the
performOperation function with different numbers and callback functions for each
mathematical operation.

Problem 4: Using the 'fs' Module

Write a Node.js program that uses the fs module to read the contents of a text file named
"notes.txt" and display them in the console.

Problem 5: Using 'os' Module

Create a Node.js program that uses the os module to display the following system
information:

● Total memory available (in bytes)


● Free memory available (in bytes)
● Operating system platform
● Number of CPU cores

Problem 6: 'lodash' Usage

Use the lodash library to solve the following problem: Given an array of numbers, write a
function that returns the sum of all even numbers in the array. Use the _.sumBy function from
lodash to achieve this.

Solution
Problem 1: NPM and Package.json

NPM (Node Package Manager) is a tool that helps you manage libraries and packages in your Node.js
projects. It allows you to easily install, update, and remove packages that you need for your project.

To create a package.json file for your project, you can use the following example:
{
"name": "my-project",
"version": "1.0.0",
"dependencies": {
"lodash": "^4.17.21"
}
}

Problem 2: Writing Functions

function calculateCircleArea(radius) {
return Math.PI * radius ** 2;
}

console.log(calculateCircleArea(5)); // Output: 78.53981633974483


console.log(calculateCircleArea(10)); // Output: 314.1592653589793

Problem 3: Callback Functions

function performOperation(num1, num2, operationCallback) {


return operationCallback(num1, num2);
}

function add(x, y) {
return x + y;
}

function subtract(x, y) {
return x - y;
}

function multiply(x, y) {
return x * y;
}

function divide(x, y) {
return x / y;
}

console.log(performOperation(10, 5, add)); // Output: 15


console.log(performOperation(10, 5, subtract)); // Output: 5
console.log(performOperation(10, 5, multiply)); // Output: 50
console.log(performOperation(10, 5, divide)); // Output: 2
Problem 4: Using 'fs' Module

const fs = require('fs');

fs.readFile('notes.txt', 'utf8', (err, data) => {


if (err) {
console.error("Error reading file:", err);
return;
}
console.log(data);
});

Problem 5: Using 'os' Module

const os = require('os');

console.log("Total Memory:", os.totalmem());


console.log("Free Memory:", os.freemem());
console.log("Platform:", os.platform());
console.log("Number of CPU Cores:", os.cpus().length);

Problem 6: 'lodash' Usage

const _ = require('lodash');

function sumOfEvenNumbers(numbers) {
const evenNumbers = _.filter(numbers, num => num % 2 === 0);
return _.sumBy(evenNumbers);
}

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];


console.log(sumOfEvenNumbers(numbers)); // Output: 30 (2 + 4 + 6 + 8 + 10)
DAY - 03

Problems

Problem 1: Understanding Servers and Express.js

Explain in your own words what a server is in the context of Node.js. Then, write step-by-step instructions on
how to create a basic server using Express.js.

Problem 2: JSON Manipulation

a) Define JSON and explain its importance in web development.

b) Given a JSON data string: {"name": "Alice", "age": 25, "hobbies": ["reading",
"painting"]}, explain how you would extract the value of the "age" key.

c) How would you convert the following object into a JSON data string? {"title": "Book", "pages":
200}

Problem 3: API and Endpoints

a) Define what an API is and its role in software development.

b) Explain what an endpoint is in the context of web APIs.

c) Provide an example of an endpoint you might find in a social media application.

Problem 4: Creating a Route with Express.js

a) Explain what the HTTP GET method is used for in the context of web development.

b) Write the code to create a simple Express.js route that responds with "Hello, World!" when a user visits the
root URL ("/").
Problem 5: JSON Parsing and Object Conversion

a) Given a JSON data string: {"product": "Laptop", "price": 999.99}, explain how you would
parse it into a JavaScript object.

b) You have an object: { "name": "Bob", "age": 30 }. How would you convert it into a JSON data
string?

Problem 6: Building a Basic API

Imagine you're building an API for a weather app. Your API needs an endpoint to retrieve the current weather.
Create an Express.js route that responds with a JSON object containing the current temperature, conditions,
and city.

Solution

Problem 1: Understanding Servers and Express.js

● A server in Node.js is a computer program that receives and responds to requests from clients (like
web browsers or mobile apps) over a network. It processes requests and sends back appropriate
responses.
● To create a basic server using Express.js:

const express = require('express');


const app = express();

app.get('/', (req, res) => {


res.send('Hello from Express server!');
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Problem 2: JSON Manipulation

a) JSON (JavaScript Object Notation) is a lightweight data interchange format used to exchange data between
a server and a client. It's easy for humans to read and write, and it's easy for machines to parse and generate.

b) To extract the value of the "age" key from the JSON data:

const age = jsonObject.age;

c) To convert an object into a JSON data string:

const jsonString = JSON.stringify({"title": "Book", "pages": 200});

Problem 3: API and Endpoints

a) An API (Application Programming Interface) is a set of rules and protocols that allows different software
components to communicate and interact with each other. It defines how requests and responses should be
structured.

b) An endpoint is a specific URL (Uniform Resource Locator) that represents a particular function or service
provided by an API. It's the specific location where clients can make requests to access certain data or perform
actions.

c) Example of an endpoint in a social media app: /users/{username} to retrieve user information based on
their username.

Problem 4: Creating a Route with Express.js

a) The HTTP GET method is used to request data from a server. It's often used to retrieve information or
resources from a specified URL.

b) Code to create a simple Express.js route:

app.get('/', (req, res) => {


res.send('Hello, World!');
});
Problem 5: JSON Parsing and Object Conversion

a) To parse a JSON data string into a JavaScript object:

const jsonData = '{"product": "Laptop", "price": 999.99}';


const parsedObject = JSON.parse(jsonData);
console.log(parsedObject.product); // Output: Laptop

b) To convert an object into a JSON data string:

const objectToConvert = { "name": "Bob", "age": 30 };


const jsonString = JSON.stringify(objectToConvert);
console.log(jsonString); // Output: {"name":"Bob","age":30}

Problem 6: Building a Basic API

const express = require('express');


const app = express();

app.get('/weather', (req, res) => {


const weatherData = {
temperature: 25,
conditions: 'Sunny',
city: 'Los Angeles'
};
res.json(weatherData);
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});
DAY - 04

Problems
Question 1: Difference Between MongoDB Server & Node.js Server

Explain the difference between a MongoDB server and a Node.js server in terms of their roles and
functionalities. Provide examples of situations where you would use each server type.

Question 2: MongoDB Queries

a) Write a MongoDB query to create a new document in a collection named "students" with fields "name,"
"age," and "grade."

b) Write a MongoDB query to update the "age" field of a document in the "employees" collection with the name
"John" to 30.

c) Write a MongoDB query to delete a document from the "products" collection with the name "Product A."

d) Write a MongoDB query to retrieve all documents from the "orders" collection where the total amount is
greater than $100.

Question 3: SQL vs. MongoDB

Explain the main differences between SQL databases and MongoDB in terms of data structure, querying
language, and use cases. Provide examples of scenarios where you might choose one over the other.

Question 4: Query Comparison

Compare and contrast the following MongoDB and SQL queries for retrieving data:

a) MongoDB: db.products.find({ category: "Electronics" })

SQL: SELECT * FROM products WHERE category = "Electronics"

b) MongoDB: db.users.findOne({ username: "Alice" })

SQL: SELECT * FROM users WHERE username = "Alice"

c) MongoDB: db.orders.aggregate([{ $group: { _id: "$status", total: { $sum:


"$amount" } } }])

SQL: SELECT status, SUM(amount) as total FROM orders GROUP BY status


Solution

Question 1: Difference Between MongoDB Server & Node.js Server

Answer: The MongoDB server is responsible for storing and managing data in the MongoDB database. It
handles data storage, retrieval, and manipulation operations. On the other hand, a Node.js server is a runtime
environment that executes JavaScript code. It handles incoming requests from clients, processes them, and
can interact with databases like MongoDB to retrieve or update data. You would use a MongoDB server to
store and manage data, while a Node.js server is used to handle application logic and serve client requests.

Question 2: MongoDB Queries

a) Answer:

db.students.insertOne({ name: "John", age: 20, grade: "A" });

b) Answer:

db.employees.updateOne({ name: "John" }, { $set: { age: 30 } });

c) Answer:

db.products.deleteOne({ name: "Product A" });

d) Answer:

db.orders.find({ totalAmount: { $gt: 100 } });

Question 3: SQL vs. MongoDB

Answer: SQL databases use structured tables with rows and columns to store data, while MongoDB uses
flexible and dynamic documents in collections. SQL databases use SQL as a querying language, while
MongoDB uses a JavaScript-like syntax for queries. SQL databases are suitable for applications with
well-defined and structured data, such as financial systems. MongoDB is better for projects with changing or
unstructured data, like content management systems or real-time analytics.
Question 4: Query Comparison

a) Answer: Both queries retrieve products with the category "Electronics."

b) Answer: Both queries retrieve a user named "Alice."

c) Answer: Both queries calculate the total amount of orders grouped by status.

DAY - 05

Problems

Question 1: Create a POST Method API

Create a POST method API to store data or menu items as per the schema we discussed ( /menu )

Question 2: Create a GET Method API

Create a GET method API to List down the All Menu Items as per the schema we discussed ( /menu )

Question 3: Creating a POST API with Express and Mongoose

You're building a simple task management application. Your task is to create a POST API endpoint for adding
new tasks to the database. Assume you've already set up an Express application and connected it to your
MongoDB using Mongoose.

a) Design the Mongoose schema for a "Task" with fields for "title," "description," "priority," and "dueDate."

b) Create a POST API endpoint /api/tasks that allow clients to submit new tasks to the database. Ensure it
handles request validation and responds with the newly created task.

Question 4: Creating a GET API with Express and Mongoose

Continuing with the task management application, you need to create a GET API endpoint for retrieving a list of
tasks from the database.

Create a GET API endpoint /api/tasks that retrieve a list of all tasks from the database. Ensure it handles
errors and responds with the list of tasks in JSON format.
Solution

Answer 1: POST method API to store data or menu items as per the schema we discussed on /menu

app.post('/menu', async (req, res) => {


try {
const menuItemData = req.body; // Assuming the request
body contains menu item data

// Create a new menu item using the Mongoose model


const menuItem = new MenuItem(menuItemData);

// Save the new menu item to the database


const menu_data = await menuItem.save();

console.log('Menu item saved');


res.status(201).json(menu_data);
} catch (error) {
console.error('Error creating menu item:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

Answer 2: GET method API to List down the All Menu Items as per the schema we discussed on /menu

app.get('/menu', async (req, res) => {


try {
// Use the Mongoose model to find all menu items in the
database
const menuItems = await MenuItem.find();

// Send the list of menu items as a JSON response


res.json(menuItems);
} catch (error) {
console.error('Error fetching menu items:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

Answer 3: Creating a POST API with Express and Mongoose

a) Design the Mongoose schema for a "Task" with fields for "title," "description," "priority," and "dueDate."

const mongoose = require('mongoose');

const taskSchema = new mongoose.Schema({


title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: true,
},
priority: {
type: String,
enum: ['High', 'Medium', 'Low'],
default: 'Medium',
},
dueDate: {
type: Date,
required: true,
},
});

const Task = mongoose.model('Task', taskSchema);

module.exports = Task;
b) Create a POST API endpoint /api/tasks that allow clients to submit new tasks to the database. Ensure it
handles request validation and responds to the newly created task.

// POST /api/tasks - Create a new task


app.post('/api/tasks', async (req, res) => {
try {
const task = new Task(req.body);
await task.save();
res.status(201).send(task);
} catch (error) {
res.status(400).send(error);
}
});

Answer 4: Creating a GET API with Express and Mongoose

a) Create a GET API endpoint /api/tasks that retrieve a list of all tasks from the database

app.get('/api/tasks', async (req, res) => {


try {
const tasks = await Task.find();
res.status(200).send(tasks);
} catch (error) {
res.status(500).send(error);
}
});
DAY - 06

Problems

Question 1: Create a parameterized GET Method API for the Menu Item on the Basis of
taste Type via using Express Router

( /menu/:taste )

Question 2: Create a PUT Method API to update the MenuItem Records ( menu/:id )

Question 3: Create a DELETE Method API to delete the MenuItem Records ( menu/:id )

Solution

Answer 1: parameterized GET Method API

router.get('/:taste', async (req, res) =>{


try{
const tasteType = req.params.taste; // // Extract the taste type
from the URL parameter
if(tasteType == 'sweet' || tasteType == 'sour' || tasteType ==
'spicy' ){
const response = await MenuItem.find({taste: tasteType});
console.log('response fetched');
res.status(200).json(response);
}else{
res.status(404).json({error: 'Invalid Taste type'});
}
}catch(err){
console.log(err);
res.status(500).json({error: 'Internal Server Error'});
}
})
Answer 2: Update Menu Item Method API

router.put('/:id', async (req, res)=>{


try{
const menuId = req.params.id; // Extract the id of Menu Item from the
URL parameter
const updatedMenuData = req.body; // Updated data for the Menu Item

const response = await MenuItem.findByIdAndUpdate(menuId,


updatedMenuData, {
new: true, // Return the updated document
runValidators: true, // Run Mongoose validation
})

if (!response) {
return res.status(404).json({ error: 'Menu Item not found' });
}

console.log('data updated');
res.status(200).json(response);
}catch(err){
console.log(err);
res.status(500).json({error: 'Internal Server Error'});
}
})

Answer 3: Delete Menu Item Method API

router.delete('/:id', async (req, res) => {


try{
const menuId = req.params.id; // Extract the Menu's ID from the URL
parameter
// Assuming you have a MenuItem model
const response = await MenuItem.findByIdAndRemove(menuId);
if (!response) {
return res.status(404).json({ error: 'Menu Item not found' });
}
console.log('data delete');
res.status(200).json({message: 'Menu Deleted Successfully'});
}catch(err){
console.log(err);
res.status(500).json({error: 'Internal Server Error'});
}
})

You might also like