Skip to content

Commit 3514298

Browse files
committed
feat: server side validation implemented
1 parent d4f6a09 commit 3514298

File tree

12 files changed

+199
-49
lines changed

12 files changed

+199
-49
lines changed

backend/package-lock.json

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"morgan": "^1.10.0",
2323
"nodemailer": "^7.0.9",
2424
"nodemon": "^3.1.10",
25-
"uuid": "^13.0.0"
25+
"uuid": "^13.0.0",
26+
"zod": "^4.1.12"
2627
},
2728
"devDependencies": {
2829
"@types/bcryptjs": "^2.4.6",

backend/src/app.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ app.use('/api/health', healthRoutes);
3636
app.use("/api/products", productRoutes);
3737
app.use("/api/users", userRoutes);
3838
app.use("/api/cart", cartRoutes);
39-
app.use("/api/users", userRoutes);
4039

4140
// MongoDB connect (optional)
4241
const mongoUri = process.env.MONGO_URI;

backend/src/middleware/auth.middleware.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// src/middleware/validateRequest.ts
2+
import { ZodObject } from "zod";
3+
import { Request, Response, NextFunction } from "express";
4+
5+
const validateRequest =
6+
(schema: ZodObject) =>
7+
(req: Request, res: Response, next: NextFunction) => {
8+
try {
9+
schema.parse({
10+
body: req.body,
11+
query: req.query,
12+
params: req.params,
13+
});
14+
next();
15+
} catch (err) {
16+
return res.status(400).json({
17+
message: "Validation failed",
18+
err
19+
// errors: err.errors.map((e: any) => e.message),
20+
});
21+
}
22+
};
23+
24+
export default validateRequest;

backend/src/routes/cartRoutes.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@ import {
66
getCart,
77
checkout,
88
} from "../controllers/cart.controller";
9-
import { authenticate } from "../middleware/authMiddleware";
9+
import { protect } from "../middleware/authMiddleware";
10+
import validateRequest from "../middleware/validateRequest";
11+
import {
12+
addItemSchema,
13+
removeItemSchema,
14+
updateQuantitySchema,
15+
getCartSchema,
16+
checkoutSchema,
17+
} from "../validations/cartValidation";
1018

1119
const router: Router = express.Router();
1220

1321
//Protected routes
14-
router.post("/", authenticate, addItem);
15-
router.patch("/:itemId", authenticate, updateQuantity);
16-
router.delete("/:itemId", authenticate, removeItem);
17-
router.get("/", authenticate, getCart);
18-
router.post("/checkout", authenticate, checkout);
22+
router.post("/add", protect, validateRequest(addItemSchema), addItem);
23+
router.patch("/:itemId", protect, validateRequest(updateQuantitySchema), updateQuantity);
24+
router.delete("/:itemId", protect, removeItem);
25+
router.get("/", protect, getCart);
26+
router.post("/checkout", protect, validateRequest(checkoutSchema), checkout);
1927

2028
export default router;

backend/src/routes/product.routes.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@ import {
77
deleteProduct,
88
} from "../controllers/product.controller";
99

10+
import {
11+
createProductSchema,
12+
updateProductSchema,
13+
getProductByIdSchema,
14+
deleteProductSchema,
15+
getProductsSchema,
16+
} from "../validations/product.validation";
17+
import validateRequest from "../middleware/validateRequest";
1018
const router = Router();
1119

12-
// router.post("/", verifyAuth, createProduct);
13-
router.post("/", createProduct);
14-
router.get("/", getProducts);
15-
router.get("/:id", getProductById);
16-
// router.put("/:id", verifyAuth, updateProduct);
17-
router.put("/:id", updateProduct);
18-
// router.delete("/:id", verifyAuth, deleteProduct);
19-
router.delete("/:id", deleteProduct);
20+
21+
router.post("/", validateRequest(createProductSchema), createProduct);
22+
router.get("/", validateRequest(getProductsSchema), getProducts);
23+
router.get("/:id", validateRequest(getProductByIdSchema), getProductById);
24+
router.put("/:id", validateRequest(updateProductSchema), updateProduct);
25+
router.delete("/:id", validateRequest(deleteProductSchema), deleteProduct);
2026

2127
export default router;
2228

backend/src/routes/user.routes.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22
import express from "express";
33
import { register, verifyEmail, login, getMe } from "../controllers/auth.controller";
44
import { protect } from "../middleware/authMiddleware";
5-
5+
import validateRequest from "../middleware/validateRequest";
6+
import {
7+
registerSchema,
8+
loginSchema,
9+
verifyEmailSchema,
10+
} from "../validations/userValidation";
611
const router = express.Router();
712

8-
router.post("/register", register);
9-
router.get("/verify/:token", verifyEmail);
10-
router.post("/login", login);
13+
router.post("/register", validateRequest(registerSchema), register);
14+
router.get("/verify/:token", validateRequest(verifyEmailSchema), verifyEmail);
15+
router.post("/login", validateRequest(loginSchema), login);
1116
router.get("/me", protect, getMe);
1217

1318
export default router;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { z } from "zod";
2+
3+
export const addItemSchema = z.object({
4+
body: z.object({
5+
productId: z.string().min(1, "Product ID is required"),
6+
name: z.string().min(2, "Product name is required"),
7+
price: z.number().positive("Price must be positive"),
8+
quantity: z.number().int().positive("Quantity must be a positive integer"),
9+
}),
10+
});
11+
12+
export const removeItemSchema = z.object({
13+
params: z.object({
14+
itemId: z.string().min(1, "Item ID is required"),
15+
}),
16+
});
17+
18+
export const updateQuantitySchema = z.object({
19+
params: z.object({
20+
itemId: z.string().min(1, "Item ID is required"),
21+
}),
22+
body: z.object({
23+
quantity: z.number().int().positive("Quantity must be a positive integer"),
24+
}),
25+
});
26+
27+
export const getCartSchema = z.object({});
28+
29+
export const checkoutSchema = z.object({});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// src/validations/product.validation.ts
2+
import { z } from "zod";
3+
4+
export const createProductSchema = z.object({
5+
body: z.object({
6+
name: z.string().min(1, "Name is required"),
7+
description: z.string().min(1, "Description is required"),
8+
price: z.number().positive(),
9+
category: z.string().optional(),
10+
stock: z.number().optional(),
11+
}),
12+
});
13+
14+
export const updateProductSchema = z.object({
15+
params: z.object({
16+
id: z.string(),
17+
}),
18+
body: z.object({
19+
name: z.string().optional(),
20+
description: z.string().optional(),
21+
price: z.number().optional(),
22+
category: z.string().optional(),
23+
stock: z.number().optional(),
24+
}),
25+
});
26+
27+
export const getProductByIdSchema = z.object({
28+
params: z.object({
29+
id: z.string(),
30+
}),
31+
});
32+
33+
export const deleteProductSchema = z.object({
34+
params: z.object({
35+
id: z.string(),
36+
}),
37+
});
38+
39+
export const getProductsSchema = z.object({
40+
query: z.object({
41+
search: z.string().optional(),
42+
category: z.string().optional(),
43+
minPrice: z.string().optional(),
44+
maxPrice: z.string().optional(),
45+
sort: z.enum(["asc", "desc", "lowToHigh", "highToLow"]).optional(),
46+
}),
47+
});

0 commit comments

Comments
 (0)