From 4f35ed1abd84f6abfa57fccda3712ec4b9a4434f Mon Sep 17 00:00:00 2001 From: Justin xzHome Date: Sun, 6 Jul 2025 22:38:21 +0900 Subject: [PATCH] Drizzle-zod for validation - part1 --- api/package-lock.json | 23 ++++++++++++++++++++- api/package.json | 6 ++++-- api/src/middlewares/validationMiddleware.ts | 20 ++++++++++++++++++ api/src/routes/products/index.ts | 14 ++++++++++++- 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 api/src/middlewares/validationMiddleware.ts diff --git a/api/package-lock.json b/api/package-lock.json index 768c713..f88cc7f 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -10,8 +10,10 @@ "license": "ISC", "dependencies": { "drizzle-orm": "^0.44.2", + "drizzle-zod": "^0.8.2", "express": "^5.1.0", - "mysql2": "^3.14.1" + "mysql2": "^3.14.1", + "zod": "^3.25.74" }, "devDependencies": { "@types/express": "^5.0.3", @@ -1297,6 +1299,16 @@ } } }, + "node_modules/drizzle-zod": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/drizzle-zod/-/drizzle-zod-0.8.2.tgz", + "integrity": "sha512-9Do/16OjFFNrQDZgvMtxtDDwKWbFOxUAIwNPKX98SfxrP8H18vhN1BvNXbhelLcdgCE7GEaXDJqBjMExSkhpkA==", + "license": "Apache-2.0", + "peerDependencies": { + "drizzle-orm": ">=0.36.0", + "zod": "^3.25.1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2214,6 +2226,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" + }, + "node_modules/zod": { + "version": "3.25.74", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.74.tgz", + "integrity": "sha512-J8poo92VuhKjNknViHRAIuuN6li/EwFbAC8OedzI8uxpEPGiXHGQu9wemIAioIpqgfB4SySaJhdk0mH5Y4ICBg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/api/package.json b/api/package.json index 5f1c833..e732836 100644 --- a/api/package.json +++ b/api/package.json @@ -12,12 +12,14 @@ "build": "tsc", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", - "db:studio" : "drizzle-kit studio" + "db:studio": "drizzle-kit studio" }, "dependencies": { "drizzle-orm": "^0.44.2", + "drizzle-zod": "^0.8.2", "express": "^5.1.0", - "mysql2": "^3.14.1" + "mysql2": "^3.14.1", + "zod": "^3.25.74" }, "devDependencies": { "@types/express": "^5.0.3", diff --git a/api/src/middlewares/validationMiddleware.ts b/api/src/middlewares/validationMiddleware.ts new file mode 100644 index 0000000..fb9bff8 --- /dev/null +++ b/api/src/middlewares/validationMiddleware.ts @@ -0,0 +1,20 @@ +import { Request, Response, NextFunction } from 'express'; +import { z, ZodError } from 'zod'; + +export function validateData(schema: z.ZodObject) { + return (req: Request, res: Response, next: NextFunction) => { + try { + schema.parse(req.body); + next(); + } catch (error) { + if (error instanceof ZodError) { + const errorMessages = error.errors.map((issue: any) => ({ + message: `${issue.path.join('.')} is ${issue.message}`, + })); + res.status(400).json({ error: 'Invalid data', details: errorMessages }); + } else { + res.status(500).json({ error: 'Internal Server Error' }); + } + } + }; +} \ No newline at end of file diff --git a/api/src/routes/products/index.ts b/api/src/routes/products/index.ts index 08e9255..7962cd2 100644 --- a/api/src/routes/products/index.ts +++ b/api/src/routes/products/index.ts @@ -5,13 +5,25 @@ import { listProducts, updateProduct, deleteProduct } from "./productsController"; +import { validateData } from "../../middlewares/validationMiddleware"; +import { z } from 'zod'; +import { createInsertSchema , createSelectSchema, createUpdateSchema } from 'drizzle-zod'; +import { productsTable } from "../../db/productsSchema"; + +const createProductSchema = z.object({ + name: z.string(), + price: z.number({ message: "not a number you idiot."}), +}); + +// const createProductSchema = createInsertSchema(productsTable); +// type ProductType = z.infer; const router = Router(); // products endpoints where validator can be added later router.get('/', listProducts); router.get('/:id', getProductById); -router.post('/', createProduct); +router.post('/', validateData(createProductSchema), createProduct); router.put('/:id', updateProduct); router.delete('/:id', deleteProduct);