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,