From 88b967dfb89c603673bcb2ac96e97fe5ac31cfb4 Mon Sep 17 00:00:00 2001 From: martmull Date: Fri, 23 May 2025 17:00:45 +0200 Subject: [PATCH] Cast typeorm QueryFailedError to BadRequestException for the rest api (#12217) --- .../filters/billing-api-exception.filter.ts | 3 ++- .../http-exception-handler.service.ts | 23 +++++++++++++------ ...st-api-core-create-one.integration-spec.ts | 19 +++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/billing/filters/billing-api-exception.filter.ts b/packages/twenty-server/src/engine/core-modules/billing/filters/billing-api-exception.filter.ts index 81588c182..8b8055c08 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/filters/billing-api-exception.filter.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/filters/billing-api-exception.filter.ts @@ -10,6 +10,7 @@ import { BillingExceptionCode, } from 'src/engine/core-modules/billing/billing.exception'; import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service'; +import { CustomException } from 'src/utils/custom-exception'; @Catch(BillingException, Stripe.errors.StripeError) export class BillingRestApiExceptionFilter implements ExceptionFilter { @@ -30,7 +31,7 @@ export class BillingRestApiExceptionFilter implements ExceptionFilter { code: BillingExceptionCode.BILLING_STRIPE_ERROR, message: exception.message, name: 'StripeError', - }, + } as CustomException, response, 400, ); diff --git a/packages/twenty-server/src/engine/core-modules/exception-handler/http-exception-handler.service.ts b/packages/twenty-server/src/engine/core-modules/exception-handler/http-exception-handler.service.ts index 0ee479337..fc118ca5e 100644 --- a/packages/twenty-server/src/engine/core-modules/exception-handler/http-exception-handler.service.ts +++ b/packages/twenty-server/src/engine/core-modules/exception-handler/http-exception-handler.service.ts @@ -1,14 +1,14 @@ -import { Inject, Injectable, Scope } from '@nestjs/common'; +import { BadRequestException, Inject, Injectable, Scope } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { Response } from 'express'; +import { QueryFailedError } from 'typeorm'; import { ExceptionHandlerUser } from 'src/engine/core-modules/exception-handler/interfaces/exception-handler-user.interface'; import { ExceptionHandlerWorkspace } from 'src/engine/core-modules/exception-handler/interfaces/exception-handler-workspace.interface'; import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; import { handleException } from 'src/engine/utils/global-exception-handler.util'; -import { CustomException } from 'src/utils/custom-exception'; interface RequestAndParams { request: Request | null; @@ -25,7 +25,7 @@ export class HttpExceptionHandlerService { ) {} handleError = ( - exception: CustomException, + exception: Error, // eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any response: Response>, @@ -37,11 +37,20 @@ export class HttpExceptionHandlerService { ): Response> | undefined => { const params = this.request?.params; - if (params?.workspaceId) + if (params?.workspaceId) { workspace = { ...workspace, id: params.workspaceId }; - if (params?.userId) user = { ...user, id: params.userId }; + } - const statusCode = errorCode || 500; + if (params?.userId) { + user = { ...user, id: params.userId }; + } + + let statusCode = errorCode || 500; + + if (exception instanceof QueryFailedError) { + exception = new BadRequestException(exception.message); + statusCode = 400; + } handleException({ exception, @@ -53,7 +62,7 @@ export class HttpExceptionHandlerService { return response.status(statusCode).send({ statusCode, - error: exception.name || 'Bad Request', + error: exception.name || 'BadRequestException', messages: [exception?.message], }); }; diff --git a/packages/twenty-server/test/integration/rest/suites/rest-api-core-create-one.integration-spec.ts b/packages/twenty-server/test/integration/rest/suites/rest-api-core-create-one.integration-spec.ts index 84adc80f1..97e35d51d 100644 --- a/packages/twenty-server/test/integration/rest/suites/rest-api-core-create-one.integration-spec.ts +++ b/packages/twenty-server/test/integration/rest/suites/rest-api-core-create-one.integration-spec.ts @@ -193,4 +193,23 @@ describe('Core REST API Create One endpoint', () => { expect(res.body.error).toBe('BadRequestException'); }); }); + + it('should return a BadRequestException when trying to create an opportunity with an invalid enum', async () => { + const requestBody = { + stage: 'INVALID_ENUM_VALUE', + }; + + await makeRestAPIRequest({ + method: 'post', + path: `/opportunities`, + body: requestBody, + }) + .expect(400) + .expect((res) => { + expect(res.body.messages[0]).toMatch( + /invalid input value for enum workspace_[a-z0-9]+\.opportunity_stage_enum: "INVALID_ENUM_VALUE"/, + ); + expect(res.body.error).toBe('BadRequestException'); + }); + }); });