Skip to content

Commit 64a2da5

Browse files
committed
feat: add zod validation for user route
1 parent 4deac7a commit 64a2da5

File tree

8 files changed

+86
-11
lines changed

8 files changed

+86
-11
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"dotenv": "^16.0.3",
1919
"express": "^4.18.2",
2020
"helmet": "^8.1.0",
21-
"mongoose": "^8.16.0"
21+
"mongoose": "^8.16.0",
22+
"zod": "^3.25.67"
2223
},
2324
"devDependencies": {
2425
"@biomejs/biome": "2.0.0",

pnpm-lock.yaml

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

src/controller/index.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +0,0 @@
1-
import { userController } from "./user.controller";
2-
3-
const controllers = {
4-
userController,
5-
};
6-
7-
export default controllers;

src/controller/user.controller.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Request, Response } from "express";
22
import { User } from "@/models/users.model";
3+
import { CreateUserInput } from "@/schemas/user.schema";
34

4-
export const userController = async (
5+
const getUsers = async (
56
_req: Request,
67
res: Response,
78
): Promise<void> => {
@@ -12,3 +13,31 @@ export const userController = async (
1213
data: allUsers,
1314
});
1415
};
16+
17+
const createUser = async (
18+
req: Request<{}, {}, CreateUserInput>,
19+
res: Response
20+
): Promise<void> => {
21+
try {
22+
const user = new User(req.body);
23+
await user.save();
24+
25+
res.status(201).json({
26+
status: 201,
27+
message: "User created successfully",
28+
data: user,
29+
});
30+
} catch (error) {
31+
res.status(500).json({
32+
status: 500,
33+
message: "Failed to create user",
34+
error: (error as Error).message,
35+
});
36+
}
37+
};
38+
39+
export const userController = {
40+
getUsers,
41+
createUser,
42+
};
43+

src/middlewares/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import globalErrorHandler from "./globalErrorHandler";
22
import notFoundRoute from "./notFoundRoute";
3+
import { validate } from "./validate";
34

45
export const middlewares = {
56
notFoundRoute,
67
globalErrorHandler,
8+
validate
79
};

src/middlewares/validate.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { ZodSchema } from "zod";
2+
import { Request, Response, NextFunction } from "express";
3+
4+
export const validate =
5+
(schema: ZodSchema<any>, source: "body" | "params" | "query" = "body") =>
6+
(req: Request, res: Response, next: NextFunction) => {
7+
const result = schema.safeParse(req[source]);
8+
9+
if (!result.success) {
10+
return res.status(400).json({
11+
message: "Validation failed",
12+
success: false,
13+
error: result.error.errors,
14+
});
15+
}
16+
17+
// overwrite with parsed data
18+
req[source] = result.data;
19+
next();
20+
};
21+

src/routes/users.routes.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import controllers from "@/controller";
1+
import { userController } from "@/controller/user.controller";
2+
import { middlewares } from "@/middlewares";
3+
import { createUserSchema } from "@/schemas/user.schema";
24
import { Router } from "express";
35

46
const userRoute = Router();
57

6-
userRoute.get("/", controllers.userController);
8+
userRoute.post("/", middlewares.validate(createUserSchema), userController.createUser);
9+
userRoute.get("/", userController.getUsers);
710

811
export default userRoute;

src/schemas/user.schema.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// src/schemas/user.schema.ts
2+
import { z } from "zod";
3+
4+
// Schema to validate user creation
5+
export const createUserSchema = z.object({
6+
name: z.string().min(1, "Name is required"),
7+
age: z.number().int().min(0).max(120),
8+
email: z.string().email(),
9+
isActive: z.boolean().optional(),
10+
});
11+
12+
// Schema to validate user update (partial fields allowed)
13+
export const updateUserSchema = createUserSchema.partial();
14+
15+
// Zod inferred types for use in TypeScript
16+
export type CreateUserInput = z.infer<typeof createUserSchema>;
17+
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
18+

0 commit comments

Comments
 (0)