diff --git a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts index 326f991bb..80cc0149c 100644 --- a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts @@ -13,6 +13,7 @@ import { ConflictError, MethodNotAllowedError, TimeoutError, + ErrorCode, } from 'src/engine/utils/graphql-errors.util'; import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; @@ -26,6 +27,17 @@ const graphQLPredefinedExceptions = { 409: ConflictError, }; +export const graphQLErrorCodesToFilter = [ + ErrorCode.GRAPHQL_VALIDATION_FAILED, + ErrorCode.UNAUTHENTICATED, + ErrorCode.FORBIDDEN, + ErrorCode.NOT_FOUND, + ErrorCode.METHOD_NOT_ALLOWED, + ErrorCode.TIMEOUT, + ErrorCode.CONFLICT, + ErrorCode.BAD_USER_INPUT, +]; + export const handleExceptionAndConvertToGraphQLError = ( exception: Error, exceptionHandlerService: ExceptionHandlerService, @@ -43,6 +55,14 @@ export const shouldFilterException = (exception: Error): boolean => { ) { return true; } + + if ( + exception instanceof BaseGraphQLError && + graphQLErrorCodesToFilter.includes(exception?.extensions?.code) + ) { + return true; + } + if (exception instanceof HttpException && exception.getStatus() < 500) { return true; } @@ -50,7 +70,7 @@ export const shouldFilterException = (exception: Error): boolean => { return false; }; -export const handleException = ( +const handleException = ( exception: Error, exceptionHandlerService: ExceptionHandlerService, user?: ExceptionHandlerUser, @@ -72,7 +92,7 @@ export const convertExceptionToGraphQLError = ( return convertExceptionToGraphql(exception); }; -export const convertHttpExceptionToGraphql = (exception: HttpException) => { +const convertHttpExceptionToGraphql = (exception: HttpException) => { const status = exception.getStatus(); let error: BaseGraphQLError; @@ -97,7 +117,10 @@ export const convertHttpExceptionToGraphql = (exception: HttpException) => { }; export const convertExceptionToGraphql = (exception: Error) => { - const error = new BaseGraphQLError(exception.name, 'INTERNAL_SERVER_ERROR'); + const error = new BaseGraphQLError( + exception.name, + ErrorCode.INTERNAL_SERVER_ERROR, + ); error.stack = exception.stack; error.extensions['response'] = exception.message; diff --git a/packages/twenty-server/src/engine/utils/graphql-errors.util.ts b/packages/twenty-server/src/engine/utils/graphql-errors.util.ts index d198a9e6e..a33cec928 100644 --- a/packages/twenty-server/src/engine/utils/graphql-errors.util.ts +++ b/packages/twenty-server/src/engine/utils/graphql-errors.util.ts @@ -15,7 +15,22 @@ declare module 'graphql' { } } -export class BaseGraphQLError extends Error implements GraphQLError { +export enum ErrorCode { + GRAPHQL_PARSE_FAILED = 'GRAPHQL_PARSE_FAILED', + GRAPHQL_VALIDATION_FAILED = 'GRAPHQL_VALIDATION_FAILED', + UNAUTHENTICATED = 'UNAUTHENTICATED', + FORBIDDEN = 'FORBIDDEN', + PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND', + PERSISTED_QUERY_NOT_SUPPORTED = 'PERSISTED_QUERY_NOT_SUPPORTED', + BAD_USER_INPUT = 'BAD_USER_INPUT', + NOT_FOUND = 'NOT_FOUND', + METHOD_NOT_ALLOWED = 'METHOD_NOT_ALLOWED', + CONFLICT = 'CONFLICT', + TIMEOUT = 'TIMEOUT', + INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', +} + +export class BaseGraphQLError extends GraphQLError { public extensions: Record; override readonly name!: string; readonly locations: ReadonlyArray | undefined; @@ -76,7 +91,7 @@ function toGraphQLError(error: BaseGraphQLError): GraphQLError { export class SyntaxError extends BaseGraphQLError { constructor(message: string) { - super(message, 'GRAPHQL_PARSE_FAILED'); + super(message, ErrorCode.GRAPHQL_PARSE_FAILED); Object.defineProperty(this, 'name', { value: 'SyntaxError' }); } @@ -84,23 +99,23 @@ export class SyntaxError extends BaseGraphQLError { export class ValidationError extends BaseGraphQLError { constructor(message: string) { - super(message, 'GRAPHQL_VALIDATION_FAILED'); + super(message, ErrorCode.GRAPHQL_VALIDATION_FAILED); Object.defineProperty(this, 'name', { value: 'ValidationError' }); } } export class AuthenticationError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'UNAUTHENTICATED', extensions); + constructor(message: string) { + super(message, ErrorCode.UNAUTHENTICATED); Object.defineProperty(this, 'name', { value: 'AuthenticationError' }); } } export class ForbiddenError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'FORBIDDEN', extensions); + constructor(message: string) { + super(message, ErrorCode.FORBIDDEN); Object.defineProperty(this, 'name', { value: 'ForbiddenError' }); } @@ -108,7 +123,7 @@ export class ForbiddenError extends BaseGraphQLError { export class PersistedQueryNotFoundError extends BaseGraphQLError { constructor() { - super('PersistedQueryNotFound', 'PERSISTED_QUERY_NOT_FOUND'); + super('PersistedQueryNotFound', ErrorCode.PERSISTED_QUERY_NOT_FOUND); Object.defineProperty(this, 'name', { value: 'PersistedQueryNotFoundError', @@ -118,7 +133,10 @@ export class PersistedQueryNotFoundError extends BaseGraphQLError { export class PersistedQueryNotSupportedError extends BaseGraphQLError { constructor() { - super('PersistedQueryNotSupported', 'PERSISTED_QUERY_NOT_SUPPORTED'); + super( + 'PersistedQueryNotSupported', + ErrorCode.PERSISTED_QUERY_NOT_SUPPORTED, + ); Object.defineProperty(this, 'name', { value: 'PersistedQueryNotSupportedError', @@ -127,40 +145,40 @@ export class PersistedQueryNotSupportedError extends BaseGraphQLError { } export class UserInputError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'BAD_USER_INPUT', extensions); + constructor(message: string) { + super(message, ErrorCode.BAD_USER_INPUT); Object.defineProperty(this, 'name', { value: 'UserInputError' }); } } export class NotFoundError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'NOT_FOUND', extensions); + constructor(message: string) { + super(message, ErrorCode.NOT_FOUND); Object.defineProperty(this, 'name', { value: 'NotFoundError' }); } } export class MethodNotAllowedError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'METHOD_NOT_ALLOWED', extensions); + constructor(message: string) { + super(message, ErrorCode.METHOD_NOT_ALLOWED); Object.defineProperty(this, 'name', { value: 'MethodNotAllowedError' }); } } export class ConflictError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'CONFLICT', extensions); + constructor(message: string) { + super(message, ErrorCode.CONFLICT); Object.defineProperty(this, 'name', { value: 'ConflictError' }); } } export class TimeoutError extends BaseGraphQLError { - constructor(message: string, extensions?: Record) { - super(message, 'TIMEOUT', extensions); + constructor(message: string) { + super(message, ErrorCode.TIMEOUT); Object.defineProperty(this, 'name', { value: 'TimeoutError' }); }