Skip to content

Commit cae9209

Browse files
authored
Merge pull request #49 from ADARSHsri2004/feat/crud_product
Feat/crud product APIS added
2 parents b15403e + 9e6aba9 commit cae9209

File tree

11 files changed

+962
-37
lines changed

11 files changed

+962
-37
lines changed

backend/package-lock.json

Lines changed: 486 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"dev": "ts-node-dev --respawn --transpile-only server.ts",
88
"build": "tsc",
9-
"start": "node dist/server.js"
9+
"start": "nodemon dist/server.js"
1010
},
1111
"author": "",
1212
"license": "MIT",
@@ -15,12 +15,16 @@
1515
"cors": "^2.8.5",
1616
"dotenv": "^16.3.1",
1717
"express": "^4.18.2",
18-
"morgan": "^1.10.0"
18+
"jsonwebtoken": "^9.0.2",
19+
"mongoose": "^8.19.1",
20+
"morgan": "^1.10.0",
21+
"nodemon": "^3.1.10"
1922
},
2023
"devDependencies": {
2124
"@types/body-parser": "^1.19.2",
2225
"@types/cors": "^2.8.13",
2326
"@types/express": "^4.17.21",
27+
"@types/jsonwebtoken": "^9.0.10",
2428
"@types/morgan": "^1.9.7",
2529
"ts-node-dev": "^2.0.0",
2630
"typescript": "^5.2.2"

backend/src/app.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import cors from 'cors';
33
import morgan from 'morgan';
44
import bodyParser from 'body-parser';
55
import healthRoutes from './routes/healthRoutes';
6-
6+
import productRoutes from "./routes/product.routes";
7+
import mongoose from "mongoose";
78
const app: Application = express();
8-
9-
9+
import dotenv from "dotenv";
10+
dotenv.config();
1011
// Middleware setup
1112
app.use(cors());
1213
app.use(morgan('dev'));
@@ -16,5 +17,16 @@ app.use(bodyParser.urlencoded({ extended: true }));
1617

1718
// API Routes
1819
app.use('/api/health', healthRoutes);
20+
app.use("/api/products", productRoutes);
21+
// Default
22+
app.get("/", (_req, res) => {
23+
res.send("API is running 🚀");
24+
});
25+
26+
// MongoDB connect (example)
27+
mongoose
28+
.connect(process.env.MONGO_URI || "")
29+
.then(() => console.log("MongoDB connected"))
30+
.catch((err) => console.error("MongoDB connection error:", err));
1931

2032
export default app;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Request, Response } from "express";
2+
import Product from "../models/product.model";
3+
4+
export const createProduct = async (req: Request, res: Response) => {
5+
try {
6+
const { name, description, price, category, stock } = req.body;
7+
8+
if (!name || !description || !price) {
9+
return res.status(400).json({ message: "Missing required fields" });
10+
}
11+
12+
const product = await Product.create({ name, description, price, category, stock });
13+
return res.status(201).json(product);
14+
} catch (error) {
15+
console.error("Create Product Error:", error);
16+
res.status(500).json({ message: "Server error" });
17+
}
18+
};
19+
20+
export const getProducts = async (_req: Request, res: Response) => {
21+
try {
22+
const products = await Product.find().sort({ createdAt: -1 });
23+
res.status(200).json(products);
24+
} catch (error) {
25+
console.error("Get Products Error:", error);
26+
res.status(500).json({ message: "Server error" });
27+
}
28+
};
29+
30+
export const getProductById = async (req: Request, res: Response) => {
31+
try {
32+
const product = await Product.findById(req.params.id);
33+
if (!product) return res.status(404).json({ message: "Product not found" });
34+
res.status(200).json(product);
35+
} catch (error) {
36+
console.error("Get Product Error:", error);
37+
res.status(500).json({ message: "Server error" });
38+
}
39+
};
40+
41+
export const updateProduct = async (req: Request, res: Response) => {
42+
try {
43+
const product = await Product.findByIdAndUpdate(req.params.id, req.body, { new: true });
44+
if (!product) return res.status(404).json({ message: "Product not found" });
45+
res.status(200).json(product);
46+
} catch (error) {
47+
console.error("Update Product Error:", error);
48+
res.status(500).json({ message: "Server error" });
49+
}
50+
};
51+
52+
export const deleteProduct = async (req: Request, res: Response) => {
53+
try {
54+
const product = await Product.findByIdAndDelete(req.params.id);
55+
if (!product) return res.status(404).json({ message: "Product not found" });
56+
res.status(200).json({ message: "Product deleted successfully" });
57+
} catch (error) {
58+
console.error("Delete Product Error:", error);
59+
res.status(500).json({ message: "Server error" });
60+
}
61+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Request, Response, NextFunction } from "express";
2+
import jwt from "jsonwebtoken";
3+
4+
const SECRET_KEY = process.env.JWT_SECRET || "your_secret_key";
5+
6+
export const verifyAuth = (req: Request, res: Response, next: NextFunction) => {
7+
const authHeader = req.headers.authorization;
8+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
9+
return res.status(401).json({ message: "Unauthorized" });
10+
}
11+
12+
const token = authHeader.split(" ")[1];
13+
try {
14+
const decoded = jwt.verify(token, SECRET_KEY);
15+
(req as any).user = decoded;
16+
next();
17+
} catch (error) {
18+
return res.status(401).json({ message: "Invalid token" });
19+
}
20+
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import mongoose, { Schema, Document } from "mongoose";
2+
3+
export interface IProduct extends Document {
4+
name: string;
5+
description: string;
6+
price: number;
7+
category?: string;
8+
stock: number;
9+
createdAt: Date;
10+
updatedAt: Date;
11+
}
12+
13+
const productSchema = new Schema<IProduct>(
14+
{
15+
name: { type: String, required: true, trim: true },
16+
description: { type: String, required: true },
17+
price: { type: Number, required: true },
18+
category: { type: String },
19+
stock: { type: Number, default: 0 },
20+
},
21+
{ timestamps: true }
22+
);
23+
24+
export default mongoose.model<IProduct>("Product", productSchema);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Router } from "express";
2+
import {
3+
createProduct,
4+
getProducts,
5+
getProductById,
6+
updateProduct,
7+
deleteProduct,
8+
} from "../controllers/product.controller";
9+
// import { verifyAuth } from "../middleware/auth.middleware";
10+
11+
const router = Router();
12+
13+
// router.post("/", verifyAuth, createProduct);
14+
router.post("/", createProduct);
15+
router.get("/", getProducts);
16+
router.get("/:id", getProductById);
17+
// router.put("/:id", verifyAuth, updateProduct);
18+
router.put("/:id", updateProduct);
19+
// router.delete("/:id", verifyAuth, deleteProduct);
20+
router.delete("/:id", deleteProduct);
21+
22+
export default router;
23+

backend/server.ts renamed to backend/src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import dotenv from 'dotenv';
22

33
dotenv.config();
44

5-
import app from './src/app';
5+
import app from './app';
66

77
const PORT = process.env.PORT ? Number(process.env.PORT) : 5000;
88

backend/tsconfig.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
22
"compilerOptions": {
33
"target": "ES2020",
4-
"module": "CommonJS",
4+
"module": "Node16",
55
"lib": ["ES2020"],
66
"outDir": "dist",
77
"rootDir": ".",
88
"strict": true,
9-
"moduleResolution": "node",
9+
"moduleResolution": "node16",
1010
"esModuleInterop": true,
1111
"skipLibCheck": true,
1212
"forceConsistentCasingInFileNames": true,
1313
"resolveJsonModule": true
1414
},
15-
"include": ["src/**/*", "server.ts"],
15+
"include": ["src"],
1616
"exclude": ["node_modules", "dist"]
17-
}
17+
}

0 commit comments

Comments
 (0)