From 1720314726a1a3eb340dc2ab3cd2150c276e426a Mon Sep 17 00:00:00 2001 From: Maria Florencia Besteiro Gonzalez Date: Fri, 31 Oct 2025 16:43:36 +0100 Subject: [PATCH] Merge pull request #29369 from overleaf/mfb-from-joi-to-zod-clsi-cache migrate from joi to zod CLSI-CACHE service GitOrigin-RevId: b583431a902a1183235cb91a270f4123a5a7e547 --- .../validation-tools/handleValidationError.js | 17 +++++++++++++++++ libraries/validation-tools/index.js | 2 ++ libraries/validation-tools/package.json | 3 ++- package-lock.json | 5 +++-- services/web/app/src/infrastructure/Server.mjs | 8 ++++---- .../web/app/src/infrastructure/Validation.js | 17 ----------------- 6 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 libraries/validation-tools/handleValidationError.js diff --git a/libraries/validation-tools/handleValidationError.js b/libraries/validation-tools/handleValidationError.js new file mode 100644 index 0000000000..8f789a83c7 --- /dev/null +++ b/libraries/validation-tools/handleValidationError.js @@ -0,0 +1,17 @@ +const { isZodErrorLike, fromError } = require('zod-validation-error') +/** + * @typedef {import('express').ErrorRequestHandler} ErrorRequestHandler + */ + +const handleValidationError = [ + /** @type {ErrorRequestHandler} */ + (err, req, res, next) => { + if (!isZodErrorLike(err)) { + return next(err) + } + + res.status(400).json({ ...fromError(err), statusCode: 400 }) + }, +] + +module.exports = { handleValidationError } diff --git a/libraries/validation-tools/index.js b/libraries/validation-tools/index.js index 0536e62b27..bce67b5e41 100644 --- a/libraries/validation-tools/index.js +++ b/libraries/validation-tools/index.js @@ -2,10 +2,12 @@ const { ParamsError } = require('./Errors') const { z } = require('zod') const { zz } = require('./zodHelpers') const { validateReq } = require('./validateReq') +const { handleValidationError } = require('./handleValidationError') module.exports = { z, zz, validateReq, + handleValidationError, ParamsError, } diff --git a/libraries/validation-tools/package.json b/libraries/validation-tools/package.json index 3aa85ff7bb..9439e7cf56 100644 --- a/libraries/validation-tools/package.json +++ b/libraries/validation-tools/package.json @@ -22,7 +22,8 @@ "dependencies": { "@overleaf/o-error": "*", "mongodb": "^6.12.0", - "zod": "^4.1.8" + "zod": "^4.1.8", + "zod-validation-error": "^4.0.1" }, "devDependencies": { "typescript": "^5.0.4", diff --git a/package-lock.json b/package-lock.json index 3846600a01..47f3623e97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -541,7 +541,8 @@ "dependencies": { "@overleaf/o-error": "*", "mongodb": "^6.12.0", - "zod": "^4.1.8" + "zod": "^4.1.8", + "zod-validation-error": "^4.0.1" }, "devDependencies": { "typescript": "^5.0.4", @@ -51424,9 +51425,9 @@ "@overleaf/promise-utils": "*", "@overleaf/settings": "*", "@overleaf/stream-utils": "*", + "@overleaf/validation-tools": "*", "body-parser": "^1.20.3", "bunyan": "^1.8.15", - "celebrate": "^15.0.3", "express": "^4.21.2", "p-limit": "^3.1.0" }, diff --git a/services/web/app/src/infrastructure/Server.mjs b/services/web/app/src/infrastructure/Server.mjs index 4e13a8e143..f3cda6b84c 100644 --- a/services/web/app/src/infrastructure/Server.mjs +++ b/services/web/app/src/infrastructure/Server.mjs @@ -2,7 +2,6 @@ import express from 'express' import Settings from '@overleaf/settings' import logger from '@overleaf/logger' import metrics from '@overleaf/metrics' -import Validation from './Validation.js' import csp, { removeCSPHeaders } from './CSP.mjs' import Router from '../router.mjs' import helmet from 'helmet' @@ -38,6 +37,7 @@ import os from 'node:os' import http from 'node:http' import { fileURLToPath } from 'node:url' import serveStaticWrapper from './ServeStaticWrapper.mjs' +import { handleValidationError } from '@overleaf/validation-tools' const { hasAdminAccess } = AdminAuthorizationHelper const sessionsRedisClient = UserSessionsRedis.client() @@ -356,17 +356,17 @@ const server = http.createServer(app) if (Settings.enabledServices.includes('api')) { logger.debug({}, 'providing api router') app.use(privateApiRouter) - app.use(Validation.errorMiddleware) + app.use(handleValidationError) app.use(ErrorController.handleApiError) } if (Settings.enabledServices.includes('web')) { logger.debug({}, 'providing web router') app.use(publicApiRouter) // public API goes with web router for public access - app.use(Validation.errorMiddleware) + app.use(handleValidationError) app.use(ErrorController.handleApiError) app.use(webRouter) - app.use(Validation.errorMiddleware) + app.use(handleValidationError) app.use(ErrorController.handleError) } diff --git a/services/web/app/src/infrastructure/Validation.js b/services/web/app/src/infrastructure/Validation.js index 8e8c9e572b..209f56a848 100644 --- a/services/web/app/src/infrastructure/Validation.js +++ b/services/web/app/src/infrastructure/Validation.js @@ -7,22 +7,6 @@ const { zz, ParamsError, } = require('@overleaf/validation-tools') -const { isZodErrorLike, fromError } = require('zod-validation-error') - -/** - * @typedef {import('express').ErrorRequestHandler} ErrorRequestHandler - */ - -const errorMiddleware = [ - /** @type {ErrorRequestHandler} */ - (err, req, res, next) => { - if (!isZodErrorLike(err)) { - return next(err) - } - - res.status(400).json({ ...fromError(err), statusCode: 400 }) - }, -] const validateReqWeb = (req, schema) => { try { @@ -37,7 +21,6 @@ const validateReqWeb = (req, schema) => { } module.exports = { - errorMiddleware, validateReq: validateReqWeb, z, zz,