MERN role-based app | Node js backend

index.js import express from "express"; import cors from "cors"; import session from "express-session"; import dotenv from "dotenv"; import db from "./config/Database.js"; // import SequelizeStore from "connect-session-sequelize"; import UserRoute from "./routes/UserRoute.js"; import ProductRoute from "./routes/ProductRoute.js"; import AuthRoute from "./routes/AuthRoute.js"; dotenv.config(); const app = express(); // const sessionStore = SequelizeStore(session.Store); // const store = new sessionStore({ // db: db // }); // (async()=>{ // await db.sync(); // })(); app.use(session({ secret: process.env.SESS_SECRET, resave: false, saveUninitialized: true, // store: store, cookie: { secure: 'auto' } })); app.use(cors({ credentials: true, origin: 'http://localhost:3000' })); app.use(express.json()); app.use(UserRoute); app.use(ProductRoute); app.use(AuthRoute); // store.sync(); app.listen(process.env.APP_PORT, ()=> { console.log('Server up and running...'); }); Routes UserRoute.js import express from "express"; import { getUsers, getUserById, createUser, updateUser, deleteUser } from "../controllers/Users.js"; import { verifyUser, adminOnly } from "../middleware/AuthUser.js"; const router = express.Router(); router.get('/users', verifyUser, getUsers); router.get('/users/:id', verifyUser, getUserById); router.post('/users', createUser); router.patch('/users/:id', verifyUser, updateUser); router.delete('/users/:id', verifyUser, deleteUser); export default router; Product Route Productroute.js import express from "express"; import { getProducts, getProductById, createProduct, updateProduct, deleteProduct } from "../controllers/Products.js"; import { verifyUser } from "../middleware/AuthUser.js"; const router = express.Router(); router.get('/products',verifyUser, getProducts); router.get('/products/:id',verifyUser, getProductById); router.post('/products',verifyUser, createProduct); router.patch('/products/:id',verifyUser, updateProduct); router.delete('/products/:id',verifyUser, deleteProduct); export default router; AuthRoute authroute.js import express from "express"; import {Login, logOut, Me} from "../controllers/Auth.js"; const router = express.Router(); router.get('/me', Me); router.post('/login', Login); router.delete('/logout', logOut); export default router; Model UserModel.js import { Sequelize } from "sequelize"; import db from "../config/Database.js"; const {DataTypes} = Sequelize; const Users = db.define('users',{ uuid:{ type: DataTypes.STRING, defaultValue: DataTypes.UUIDV4, allowNull: false, validate:{ notEmpty: true } }, name:{ type: DataTypes.STRING, allowNull: false, validate:{ notEmpty: true, len: [3, 100] } }, email:{ type: DataTypes.STRING, allowNull: false, validate:{ notEmpty: true, isEmail: true } }, password:{ type: DataTypes.STRING, allowNull: false, validate:{ notEmpty: true } }, role:{ type: DataTypes.STRING, allowNull: false, validate:{ notEmpty: true } } },{ freezeTableName: true }); export default Users; ProductModel.js import { Sequelize } from "sequelize"; import db from "../config/Database.js"; import Users from "./UserModel.js"; const {DataTypes} = Sequelize; const Products = db.define('product',{ uuid:{ type: DataTypes.STRING, defaultValue: DataTypes.UUIDV4, allowNull: false, validate:{ notEmpty: true } }, name:{ type: DataTypes.STRING, allowNull: false, validate:{ notEmpty: true, len: [3, 100] } }, price:{ type: DataTypes.INTEGER, allowNull: false, validate:{ notEmpty: true } }, userId:{ type: DataTypes.INTEGER, allowNull: false, validate:{ notEmpty: true } } },{ freezeTableName: true }); Users.hasMany(Products); Products.belongsTo(Users, {foreignKey: 'userId'}); export default Products; Middleware Authmiddleware.js import User from "../models/UserModel.js"; export const verifyUser = async (req, res, next) =>{ if(!req.session.userId){ return res.status(401).json({msg: "Please login to your account!"}); } const user = await User.findOne({ where: { uuid: req.session.userId } }); if(!user) return res.status(404).json({msg: "User not found"}); req.userId = user.id; req.role = user.role; next(); } expor

Mar 4, 2025 - 09:55
 0
MERN role-based app | Node js backend

index.js

import express from "express";
import cors from "cors";
import session from "express-session";
import dotenv from "dotenv";
import db from "./config/Database.js";
// import SequelizeStore from "connect-session-sequelize";
import UserRoute from "./routes/UserRoute.js";
import ProductRoute from "./routes/ProductRoute.js";
import AuthRoute from "./routes/AuthRoute.js";
dotenv.config();

const app = express();

// const sessionStore = SequelizeStore(session.Store);

// const store = new sessionStore({
//     db: db
// });

// (async()=>{
//     await db.sync();
// })();


app.use(session({
    secret: process.env.SESS_SECRET,
    resave: false,
    saveUninitialized: true,
    // store: store,
    cookie: {
        secure: 'auto'
    }
}));

app.use(cors({
    credentials: true,
    origin: 'http://localhost:3000'
}));
app.use(express.json());
app.use(UserRoute);
app.use(ProductRoute);
app.use(AuthRoute);
// store.sync();


app.listen(process.env.APP_PORT, ()=> {
    console.log('Server up and running...');
});

Routes

UserRoute.js

import express from "express";
import {
    getUsers,
    getUserById,
    createUser,
    updateUser,
    deleteUser
} from "../controllers/Users.js";
import { verifyUser, adminOnly } from "../middleware/AuthUser.js";

const router = express.Router();

router.get('/users', verifyUser, getUsers);
router.get('/users/:id', verifyUser, getUserById);
router.post('/users', createUser);
router.patch('/users/:id', verifyUser, updateUser);
router.delete('/users/:id', verifyUser, deleteUser);

export default router;

Product Route

Productroute.js

import express from "express";
import {
    getProducts,
    getProductById,
    createProduct,
    updateProduct,
    deleteProduct
} from "../controllers/Products.js";
import { verifyUser } from "../middleware/AuthUser.js";

const router = express.Router();

router.get('/products',verifyUser, getProducts);
router.get('/products/:id',verifyUser, getProductById);
router.post('/products',verifyUser, createProduct);
router.patch('/products/:id',verifyUser, updateProduct);
router.delete('/products/:id',verifyUser, deleteProduct);

export default router;

AuthRoute

authroute.js

import express from "express";
import {Login, logOut, Me} from "../controllers/Auth.js";

const router = express.Router();

router.get('/me', Me);
router.post('/login', Login);
router.delete('/logout', logOut);

export default router;

Model

UserModel.js

import { Sequelize } from "sequelize";
import db from "../config/Database.js";

const {DataTypes} = Sequelize;

const Users = db.define('users',{
    uuid:{
        type: DataTypes.STRING,
        defaultValue: DataTypes.UUIDV4,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    },
    name:{
        type: DataTypes.STRING,
        allowNull: false,
        validate:{
            notEmpty: true,
            len: [3, 100]
        }
    },
    email:{
        type: DataTypes.STRING,
        allowNull: false,
        validate:{
            notEmpty: true,
            isEmail: true
        }
    },
    password:{
        type: DataTypes.STRING,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    },
    role:{
        type: DataTypes.STRING,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    }
},{
    freezeTableName: true
});

export default Users;

ProductModel.js

import { Sequelize } from "sequelize";
import db from "../config/Database.js";
import Users from "./UserModel.js";

const {DataTypes} = Sequelize;

const Products = db.define('product',{
    uuid:{
        type: DataTypes.STRING,
        defaultValue: DataTypes.UUIDV4,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    },
    name:{
        type: DataTypes.STRING,
        allowNull: false,
        validate:{
            notEmpty: true,
            len: [3, 100]
        }
    },
    price:{
        type: DataTypes.INTEGER,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    },
    userId:{
        type: DataTypes.INTEGER,
        allowNull: false,
        validate:{
            notEmpty: true
        }
    }
},{
    freezeTableName: true
});

Users.hasMany(Products);
Products.belongsTo(Users, {foreignKey: 'userId'});

export default Products;

Middleware

Authmiddleware.js

import User from "../models/UserModel.js";

export const verifyUser = async (req, res, next) =>{
    if(!req.session.userId){
        return res.status(401).json({msg: "Please login to your account!"});
    }
    const user = await User.findOne({
        where: {
            uuid: req.session.userId
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    req.userId = user.id;
    req.role = user.role; 
    next();
}



export const adminOnly = async (req, res, next) =>{
    const user = await User.findOne({
        where: {
            uuid: req.session.userId
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    if(user.role !== "admin") return res.status(403).json({msg: "Access prohibited"});
    next();
}

Controller

User.js

import User from "../models/UserModel.js";

export const verifyUser = async (req, res, next) =>{
    if(!req.session.userId){
        return res.status(401).json({msg: "Please login to your account!"});
    }
    const user = await User.findOne({
        where: {
            uuid: req.session.userId
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    req.userId = user.id;
    req.role = user.role; 
    next();
}



export const adminOnly = async (req, res, next) =>{
    const user = await User.findOne({
        where: {
            uuid: req.session.userId
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    if(user.role !== "admin") return res.status(403).json({msg: "Access prohibited"});
    next();
}

Products.js

import Product from "../models/ProductModel.js";
import User from "../models/UserModel.js";
import { Op } from "sequelize";

export const getProducts = async (req, res) => {
    try {
        let response;
        if (req.role === "admin") {
            response = await Product.findAll({
                attributes: ['uuid', 'name', 'price'],
                include: [{
                    model: User,
                    attributes: ['name', 'email']
                }]
            });
        } else {
            response = await Product.findAll({
                attributes: ['uuid', 'name', 'price'],
                where: {
                    userId: req.userId
                },
                include: [{
                    model: User,
                    attributes: ['name', 'email']
                }]
            });
        }
        res.status(200).json(response);
    } catch (error) {
        res.status(500).json({ msg: error.message });
    }
}

export const getProductById = async (req, res) => {
    try {
        const product = await Product.findOne({
            where: {
                uuid: req.params.id
            }
        });
        if (!product) return res.status(404).json({ msg: "Data tidak ditemukan" });
        let response;
        if (req.role === "admin") {
            response = await Product.findOne({
                attributes: ['uuid', 'name', 'price'],
                where: {
                    id: product.id
                },
                include: [{
                    model: User,
                    attributes: ['name', 'email']
                }]
            });
        } else {
            response = await Product.findOne({
                attributes: ['uuid', 'name', 'price'],
                where: {
                    [Op.and]: [{ id: product.id }, { userId: req.userId }]
                },
                include: [{
                    model: User,
                    attributes: ['name', 'email']
                }]
            });
        }
        res.status(200).json(response);
    } catch (error) {
        res.status(500).json({ msg: error.message });
    }
}

export const createProduct = async (req, res) => {
    const { name, price } = req.body;
    try {
        await Product.create({
            name: name,
            price: price,
            userId: req.userId
        });
        res.status(201).json({ msg: "Product Created Successfuly" });
    } catch (error) {
        res.status(500).json({ msg: error.message });
    }
}

export const updateProduct = async (req, res) => {
    try {
        const product = await Product.findOne({
            where: {
                uuid: req.params.id
            }
        });
        if (!product) return res.status(404).json({ msg: "Data tidak ditemukan" });
        const { name, price } = req.body;
        if (req.role === "admin") {
            await Product.update({ name, price }, {
                where: {
                    id: product.id
                }
            });
        } else {
            if (req.userId !== product.userId) return res.status(403).json({ msg: "Akses terlarang" });
            await Product.update({ name, price }, {
                where: {
                    [Op.and]: [{ id: product.id }, { userId: req.userId }]
                }
            });
        }
        res.status(200).json({ msg: "Product updated successfuly" });
    } catch (error) {
        res.status(500).json({ msg: error.message });
    }
}

export const deleteProduct = async (req, res) => {
    try {
        const product = await Product.findOne({
            where: {
                uuid: req.params.id
            }
        });
        if (!product) return res.status(404).json({ msg: "Data tidak ditemukan" });
        const { name, price } = req.body;
        if (req.role === "admin") {
            await Product.destroy({
                where: {
                    id: product.id
                }
            });
        } else {
            if (req.userId !== product.userId) return res.status(403).json({ msg: "Akses terlarang" });
            await Product.destroy({
                where: {
                    [Op.and]: [{ id: product.id }, { userId: req.userId }]
                }
            });
        }
        res.status(200).json({ msg: "Product deleted successfuly" });
    } catch (error) {
        res.status(500).json({ msg: error.message });
    }
}

Auth.js

import User from "../models/UserModel.js";
import argon2 from "argon2";

export const Login = async (req, res) =>{
    const user = await User.findOne({
        where: {
            email: req.body.email
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    const match = await argon2.verify(user.password, req.body.password);
    if(!match) return res.status(400).json({msg: "Wrong Password"});
    req.session.userId = user.uuid;
    const uuid  =  user.uuid;
    const name  =  user.name;
    const email =  user.email;
    const role  =  user.role;
    res.status(200).json({uuid, name, email, role});
}

export const Me = async (req, res) =>{
    if(!req.session.userId){
        return res.status(401).json({msg: "Please login to your account!!"});
    }
    const user = await User.findOne({
        attributes:['uuid','name','email','role'],
        where: {
            uuid: req.session.userId
        }
    });
    if(!user) return res.status(404).json({msg: "User not found"});
    res.status(200).json(user);
}
export const logOut = (req, res) =>{
    req.session.destroy((err)=>{
        if(err) return res.status(400).json({msg: "Cannot log out"});
        res.status(200).json({msg: "You have logged out"});
    });
}

Config

Database.js

import {Sequelize} from "sequelize";

const db = new Sequelize('auth_db', 'root', '', {
    host: "localhost",
    dialect: "mysql"
});

export default db;

pakage.json

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "argon2": "^0.28.7",
    "connect-session-sequelize": "^7.1.4",
    "cors": "^2.8.5",
    "dotenv": "^16.0.1",
    "express": "^4.18.1",
    "express-session": "^1.17.3",
    "mysql2": "^2.3.3",
    "sequelize": "^6.21.3"
  }
}