Files
twenty/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts
T
Weiko e2dc660d18 Fix exception handler capturing graphql errors (#5714)
Our exception handler has to filter out some errors/exceptions so they
are not caught by the ExceptionHandlerDriver (Logged or Sentry for
example). This is done for Http errors in the range of 4xx and also
makes sure they are converted back to Graphql validation errors.
However, graphql validation errors that are already managed by Yoga
(with Schema validation) should also be filtered out, this PR should fix
that behaviour
2024-06-03 14:36:03 +02:00

107 lines
2.8 KiB
TypeScript

import { HttpException } from '@nestjs/common';
import { GraphQLError } from 'graphql';
import { ExceptionHandlerUser } from 'src/engine/integrations/exception-handler/interfaces/exception-handler-user.interface';
import {
AuthenticationError,
BaseGraphQLError,
ForbiddenError,
ValidationError,
NotFoundError,
ConflictError,
MethodNotAllowedError,
TimeoutError,
} from 'src/engine/utils/graphql-errors.util';
import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service';
const graphQLPredefinedExceptions = {
400: ValidationError,
401: AuthenticationError,
403: ForbiddenError,
404: NotFoundError,
405: MethodNotAllowedError,
408: TimeoutError,
409: ConflictError,
};
export const handleExceptionAndConvertToGraphQLError = (
exception: Error,
exceptionHandlerService: ExceptionHandlerService,
user?: ExceptionHandlerUser,
): BaseGraphQLError => {
handleException(exception, exceptionHandlerService, user);
return convertExceptionToGraphQLError(exception);
};
export const shouldFilterException = (exception: Error): boolean => {
if (
exception instanceof GraphQLError &&
(exception?.extensions?.http?.status ?? 500) < 500
) {
return true;
}
if (exception instanceof HttpException && exception.getStatus() < 500) {
return true;
}
return false;
};
export const handleException = (
exception: Error,
exceptionHandlerService: ExceptionHandlerService,
user?: ExceptionHandlerUser,
): void => {
if (shouldFilterException(exception)) {
return;
}
exceptionHandlerService.captureExceptions([exception], { user });
};
export const convertExceptionToGraphQLError = (
exception: Error,
): BaseGraphQLError => {
if (exception instanceof HttpException) {
return convertHttpExceptionToGraphql(exception);
}
return convertExceptionToGraphql(exception);
};
export const convertHttpExceptionToGraphql = (exception: HttpException) => {
const status = exception.getStatus();
let error: BaseGraphQLError;
if (status in graphQLPredefinedExceptions) {
const message = exception.getResponse()['message'] ?? exception.message;
error = new graphQLPredefinedExceptions[exception.getStatus()](message);
} else {
error = new BaseGraphQLError(
'Internal Server Error',
exception.getStatus().toString(),
);
}
// Only show the stack trace in development mode
if (process.env.NODE_ENV === 'development') {
error.stack = exception.stack;
error.extensions['response'] = exception.getResponse();
}
return error;
};
export const convertExceptionToGraphql = (exception: Error) => {
const error = new BaseGraphQLError(exception.name, 'INTERNAL_SERVER_ERROR');
error.stack = exception.stack;
error.extensions['response'] = exception.message;
return error;
};