In this Post we will understand stateful as well as stateless system write some code and understand thieir benefit
Here is the repo for both stateful and stateless code
auth repo
Theory
1. StateFul System.
stateful system remember past interaction by storing state across all request.server store state
Advantage.
Simple Client Logic
Disadvantage
Hard to scale
Server must manage session
2. StateLess System
stateLess system treat each request completely independent.It doesn't know anythin about previous interaction. user need to send info by tokens.tokens are store from client side eg. inside cookies
Advantage.
High Scalability
Fault tolerance
Disadvantage
Repeated data sent every time.
practical
In this practical section we are going to use express,mongoose for our practical
First of all initialize npm then add package
express - for creating server
nodemon - for restarting server everytime any file changes
mongodb - for connection to mongodb
moongoose - for creating schema
dotenv - loading env variables
bcrypt - so that we can hash user password
create folder:- models controllers routes
npm i express nodemon mongodb mongoose dotenv bcrypt
create db.js
const mongoose = require('mongoose')
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGODB_URI)
console.log('mongodb connected');
} catch (error) {
console.log('mongodb connection error ', error);
process.exit(1)
}
}
module.exports = connectDB;
create index.js and start express server and also add db connection
stateful example
const express = require('express')
const session = require('express-session')
const authRouter = require('./routes/user.route');
const connectDB = require('./db.index');
const app = express();
const PORT = 8080;
const dotenv = require('dotenv')
dotenv.config()
app.use(express.json())
app.get('/', (req, res) => {
res.send('ok')
})
//we created a session for stateful system
app.use(session({
secret: "Navin45",
resave: false,
saveUninitialized: false
}))
app.use('/auth', authRouter)
app.listen(PORT, async () => {
await connectDB()
console.log(`server is listening http://localhost:${PORT}`)
})
In this we create 4 fuction but the import part is we attach userId session after verify it's email and password and by using this we can get user state when ever we need.
req.session.userId = user._id;
const User = require('../models/user.model.js')
const register = async (req, res) => {
try {
const { name, email, password } = req.body;
const user = await User.create({ name, email, password })
return res.status(201).json(user)
} catch (error) {
console.log(error);
}
}
const login = async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ mess: "Please enter all fields" })
}
const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ mess: "Invalid crediatels " })
}
const isValidPassword = await user.isPasswordCorrect(password)
if (!isValidPassword) {
return res.status(404).json({ mess: "Invalid crediatels " })
}
// 🛑STATEFULL PART
req.session.userId = user._id;
return res.status(200).json({ mess: "Login successfully " })
} catch (error) {
console.log(error);
return res.status(500).json({ mess: "Internal server errror" })
}
}
const logout = (req, res) => {
try {
req.session.destroy(() => {
res.json({ mess: "logout successfully" })
})
} catch (error) {
return res.status(500).json({ mess: "Internal server error" })
}
}
const dashboard = async (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ mess: "Not logged in" })
}
return res.status(200).json({
mess: "Welcome to dashboard",
userId: req.session.userId
})
}
module.exports = {
register,
login,
logout,
dashboard
}
stateless example
we uses jsonwebtoken package for maintaining stateless state
jwt contain 3 part header payload signature
npm i jsonwebtoken
const User = require('../models/user.model')
const jwt = require('jsonwebtoken')
const JWT_SECREAT = "navin5500";
const reqister = async (req, res) => {
try {
const { name, email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ mess: "please enter details" })
}
const isUserExists = await User.findOne({ email })
if (isUserExists) {
return res.status(405).json({ message: "User with this email already exists " })
}
const user = await User.create({ name, email, password })
return res.status(200).json({ message: "Use register successfully " })
} catch (error) {
console.log(error)
return res.status(500).json({ mess: "internal server error" })
}
}
const login = async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ mess: "Please enter all fields" })
}
const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ mess: "Invalid crediatels " })
}
const isValidPassword = await user.isPasswordCorrect(password)
if (!isValidPassword) {
return res.status(404).json({ mess: "Invalid crediatels " })
}
// 🛑STATELESS PART
const token = jwt.sign(
{ userId: user._id },
JWT_SECREAT,
{ expiresIn: "1h" }
)
return res.status(200).json({ mess: "Login successfully ", token })
} catch (error) {
console.log(error);
return res.status(500).json({ mess: "Internal server errror" })
}
}
const dashboard = async (req, res) => {
try {
return res.status(200).json({ mess: "Welcome to dashboard", userId: req.userId })
} catch (error) {
return res.status(500).json({ mess: "Internal server error", })
}
}
module.exports = {
reqister,
login,
dashboard,
}
This is a middleware any request will try access any imp data first will grow through this if validate then go next else it will return from here only and we also attact userId on request so that we can get user info whenver we need
const jwt = require('jsonwebtoken')
const JWT_SECREAT = "navin5500";
const checkHeader = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ message: "No token provided" });
}
const token = authHeader.split(" ")[1];
try {
const decoded = jwt.verify(token, JWT_SECREAT)
req.userId = decoded.userId;
next()
} catch (error) {
return res.status(401).json({ message: "Invalid token" });
}
}
module.exports = { checkHeader }

Top comments (0)