From a0a35bdc557d6e5c9b2bfd937ec9b4b014a29800 Mon Sep 17 00:00:00 2001 From: Samuel Lim Date: Fri, 25 Oct 2024 00:22:33 +0800 Subject: [PATCH] Match: Replace Joi with Zod --- services/match/package-lock.json | 76 ++++--------------- services/match/package.json | 5 +- .../src/controllers/matchRequestController.ts | 11 ++- .../src/validation/matchRequestValidation.ts | 10 +-- 4 files changed, 27 insertions(+), 75 deletions(-) diff --git a/services/match/package-lock.json b/services/match/package-lock.json index a5653ed5d8..286f4156bd 100644 --- a/services/match/package-lock.json +++ b/services/match/package-lock.json @@ -13,11 +13,11 @@ "body-parser": "^1.20.3", "cors": "^2.8.5", "express": "^4.21.0", - "joi": "^17.13.3", "jsonwebtoken": "^9.0.2", "mongoose": "^8.7.0", "morgan": "^1.10.0", - "zod": "^3.23.8" + "zod": "^3.23.8", + "zod-validation-error": "^3.4.0" }, "devDependencies": { "@eslint/js": "^9.10.0", @@ -25,7 +25,6 @@ "@types/cors": "^2.8.17", "@types/eslint__js": "^8.42.3", "@types/express": "^4.17.21", - "@types/joi": "^17.2.2", "@types/jsonwebtoken": "^9.0.7", "@types/mongoose": "^5.11.96", "@types/morgan": "^1.9.9", @@ -259,21 +258,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -452,27 +436,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@sideway/address": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "license": "BSD-3-Clause" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "license": "BSD-3-Clause" - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -610,16 +573,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/joi": { - "version": "17.2.2", - "resolved": "https://registry.npmjs.org/@types/joi/-/joi-17.2.2.tgz", - "integrity": "sha512-vPvPwxn0Y4pQyqkEcMCJYxXCMYcrHqdfFX4SpF4zcqYioYexmDyxtM3OK+m/ZwGBS8/dooJ0il9qCwAdd6KFtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "joi": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2510,19 +2463,6 @@ "dev": true, "license": "ISC" }, - "node_modules/joi": { - "version": "17.13.3", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", - "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.3.0", - "@hapi/topo": "^5.1.0", - "@sideway/address": "^4.1.5", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4709,6 +4649,18 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } } } } diff --git a/services/match/package.json b/services/match/package.json index 1ea677f494..9a19897aec 100644 --- a/services/match/package.json +++ b/services/match/package.json @@ -17,11 +17,11 @@ "body-parser": "^1.20.3", "cors": "^2.8.5", "express": "^4.21.0", - "joi": "^17.13.3", "jsonwebtoken": "^9.0.2", "mongoose": "^8.7.0", "morgan": "^1.10.0", - "zod": "^3.23.8" + "zod": "^3.23.8", + "zod-validation-error": "^3.4.0" }, "devDependencies": { "@eslint/js": "^9.10.0", @@ -29,7 +29,6 @@ "@types/cors": "^2.8.17", "@types/eslint__js": "^8.42.3", "@types/express": "^4.17.21", - "@types/joi": "^17.2.2", "@types/jsonwebtoken": "^9.0.7", "@types/mongoose": "^5.11.96", "@types/morgan": "^1.9.9", diff --git a/services/match/src/controllers/matchRequestController.ts b/services/match/src/controllers/matchRequestController.ts index 4600dc6940..79e0b486cb 100644 --- a/services/match/src/controllers/matchRequestController.ts +++ b/services/match/src/controllers/matchRequestController.ts @@ -10,6 +10,7 @@ import { } from '../models/repository'; import { produceMatchUpdatedRequest } from '../events/producer'; import { getStatus } from '../models/matchRequestModel'; +import { fromError } from 'zod-validation-error'; /** * Creates a match request. @@ -17,13 +18,15 @@ import { getStatus } from '../models/matchRequestModel'; * @param res */ export const createMatchRequest = async (req: Request, res: Response) => { - const { error, value } = createMatchRequestSchema.validate(req.body); - if (error) { - return handleBadRequest(res, error.message); + const result = createMatchRequestSchema.safeParse(req.body); + + if (!result.success) { + const formattedError = fromError(result.error).toString(); + return handleBadRequest(res, formattedError); } const { id: userId, username } = req.user; - const { topics, difficulty } = value; + const { topics, difficulty } = result.data; try { const matchRequest = await _createMatchRequest(userId, username, topics, difficulty); await produceMatchUpdatedRequest(matchRequest.id, userId, username, topics, difficulty); diff --git a/services/match/src/validation/matchRequestValidation.ts b/services/match/src/validation/matchRequestValidation.ts index 9c3aa4d767..7450b64816 100644 --- a/services/match/src/validation/matchRequestValidation.ts +++ b/services/match/src/validation/matchRequestValidation.ts @@ -1,9 +1,7 @@ -import Joi from 'joi'; +import { z } from 'zod'; import { Difficulty } from '../models/matchRequestModel'; -export const createMatchRequestSchema = Joi.object({ - topics: Joi.array().items(Joi.string()).min(1).required(), - difficulty: Joi.string() - .valid(...Object.values(Difficulty)) - .required(), +export const createMatchRequestSchema = z.object({ + topics: z.array(z.string().min(1)).min(1), + difficulty: z.nativeEnum(Difficulty), });