E-Commerce API Backend

 Great idea 👍 — practicing multiple setups will prepare you for any company’s exam format.

Here’s another advanced project example with full setup.


🚀 Example 2: E-Commerce API Backend

A practical, advanced Node.js + Express + Database project that covers auth, CRUD, relationships, validation, middleware, and security.


📂 Project Structure

ecommerce-api/
│── src/
│   ├── config/
│   │   └── db.js
│   ├── controllers/
│   │   ├── authController.js
│   │   ├── productController.js
│   │   └── orderController.js
│   ├── middleware/
│   │   ├── authMiddleware.js
│   │   └── errorMiddleware.js
│   ├── models/
│   │   ├── User.js
│   │   ├── Product.js
│   │   └── Order.js
│   ├── routes/
│   │   ├── authRoutes.js
│   │   ├── productRoutes.js
│   │   └── orderRoutes.js
│   ├── app.js
│   └── server.js
│── .env
│── package.json

📦 Install Dependencies

npm init -y
npm install express bcryptjs jsonwebtoken dotenv mongoose
npm install joi helmet cors morgan winston
npm install nodemon --save-dev

⚙️ src/config/db.js (MongoDB with Mongoose)

const mongoose = require("mongoose");

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGO_URI);
    console.log("MongoDB Connected");
  } catch (err) {
    console.error(err.message);
    process.exit(1);
  }
};

module.exports = connectDB;

👤 src/models/User.js

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, unique: true, required: true },
  password: { type: String, required: true },
  role: { type: String, enum: ["Customer", "Admin"], default: "Customer" },
}, { timestamps: true });

module.exports = mongoose.model("User", userSchema);

📦 src/models/Product.js

const mongoose = require("mongoose");

const productSchema = new mongoose.Schema({
  name: { type: String, required: true },
  price: { type: Number, required: true },
  stock: { type: Number, default: 0 },
}, { timestamps: true });

module.exports = mongoose.model("Product", productSchema);

🛒 src/models/Order.js

const mongoose = require("mongoose");

const orderSchema = new mongoose.Schema({
  customer: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
  products: [
    {
      product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
      quantity: { type: Number, required: true },
    },
  ],
  status: { type: String, enum: ["Pending", "Completed"], default: "Pending" },
}, { timestamps: true });

module.exports = mongoose.model("Order", orderSchema);

🔑 src/controllers/authController.js

const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");

exports.register = async (req, res, next) => {
  try {
    const { name, email, password, role } = req.body;
    const hashed = await bcrypt.hash(password, 10);
    const user = await User.create({ name, email, password: hashed, role });
    res.status(201).json({ message: "User created", user });
  } catch (err) {
    next(err);
  }
};

exports.login = async (req, res, next) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    if (!user) return res.status(401).json({ message: "Invalid credentials" });

    const valid = await bcrypt.compare(password, user.password);
    if (!valid) return res.status(401).json({ message: "Invalid credentials" });

    const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, {
      expiresIn: "1h",
    });

    res.json({ token });
  } catch (err) {
    next(err);
  }
};

📦 src/controllers/productController.js

const Product = require("../models/Product");

exports.createProduct = async (req, res, next) => {
  try {
    const product = await Product.create(req.body);
    res.status(201).json(product);
  } catch (err) {
    next(err);
  }
};

exports.getProducts = async (req, res, next) => {
  try {
    const products = await Product.find();
    res.json(products);
  } catch (err) {
    next(err);
  }
};

🛒 src/controllers/orderController.js

const Order = require("../models/Order");

exports.createOrder = async (req, res, next) => {
  try {
    const order = await Order.create({ customer: req.user.id, products: req.body.products });
    res.status(201).json(order);
  } catch (err) {
    next(err);
  }
};

exports.getMyOrders = async (req, res, next) => {
  try {
    const orders = await Order.find({ customer: req.user.id }).populate("products.product");
    res.json(orders);
  } catch (err) {
    next(err);
  }
};

🔐 src/middleware/authMiddleware.js

const jwt = require("jsonwebtoken");

exports.authMiddleware = (req, res, next) => {
  const token = req.headers["authorization"];
  if (!token) return res.status(401).json({ message: "No token provided" });

  try {
    const decoded = jwt.verify(token.split(" ")[1], process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).json({ message: "Invalid token" });
  }
};

exports.roleMiddleware = (roles) => (req, res, next) => {
  if (!roles.includes(req.user.role)) return res.status(403).json({ message: "Forbidden" });
  next();
};

🚦 src/middleware/errorMiddleware.js

exports.errorHandler = (err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: err.message });
};

🌍 Routes

src/routes/authRoutes.js

const express = require("express");
const { register, login } = require("../controllers/authController");
const router = express.Router();

router.post("/register", register);
router.post("/login", login);

module.exports = router;

src/routes/productRoutes.js

const express = require("express");
const { createProduct, getProducts } = require("../controllers/productController");
const { authMiddleware, roleMiddleware } = require("../middleware/authMiddleware");
const router = express.Router();

router.post("/", authMiddleware, roleMiddleware(["Admin"]), createProduct);
router.get("/", getProducts);

module.exports = router;

src/routes/orderRoutes.js

const express = require("express");
const { createOrder, getMyOrders } = require("../controllers/orderController");
const { authMiddleware } = require("../middleware/authMiddleware");
const router = express.Router();

router.post("/", authMiddleware, createOrder);
router.get("/", authMiddleware, getMyOrders);

module.exports = router;

🚀 src/app.js

const express = require("express");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");

const authRoutes = require("./routes/authRoutes");
const productRoutes = require("./routes/productRoutes");
const orderRoutes = require("./routes/orderRoutes");
const { errorHandler } = require("./middleware/errorMiddleware");

dotenv.config();
const app = express();

app.use(express.json());
app.use(helmet());
app.use(morgan("dev"));

app.use("/api/auth", authRoutes);
app.use("/api/products", productRoutes);
app.use("/api/orders", orderRoutes);

app.use(errorHandler);

module.exports = app;

🖥️ src/server.js

const app = require("./app");
const connectDB = require("./config/db");

const PORT = process.env.PORT || 5000;

connectDB();
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

🔑 .env

PORT=5000
MONGO_URI=mongodb://localhost:27017/ecommerce
JWT_SECRET=supersecretkey

✅ This E-Commerce API project tests:

  • Authentication (JWT + Roles)

  • CRUD (Products, Orders)

  • Database Relations (User ↔ Orders, Orders ↔ Products)

  • Middleware (Auth, Role-based access, Error handling)

  • Security (Helmet, hashed passwords)


Would you like me to now build a step-by-step 3-hour practice plan (like a roadmap: 30 min DB setup, 1 hr Auth, 1 hr Orders/Products, 30 min extras) for this project, so you can simulate the exam under time pressure?

Previous Post Next Post