From 1d025df57743a2ee244817a90bf1302f47535691 Mon Sep 17 00:00:00 2001 From: Eric Cabrel TIOGO Date: Fri, 12 Jul 2024 12:07:59 +0200 Subject: [PATCH] fix(backend): catch prisma error globally --- .changeset/wet-yaks-knock.md | 5 +++ apps/backend/src/configs/exception.filter.ts | 45 ++++++++++++++++++-- apps/backend/src/utils/constants.ts | 2 + 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 .changeset/wet-yaks-knock.md diff --git a/.changeset/wet-yaks-knock.md b/.changeset/wet-yaks-knock.md new file mode 100644 index 00000000..2689311c --- /dev/null +++ b/.changeset/wet-yaks-knock.md @@ -0,0 +1,5 @@ +--- +'@snipcode/backend': patch +--- + +Catch Prisma technical error and return user friendly message diff --git a/apps/backend/src/configs/exception.filter.ts b/apps/backend/src/configs/exception.filter.ts index 0e1b4271..484bce3c 100644 --- a/apps/backend/src/configs/exception.filter.ts +++ b/apps/backend/src/configs/exception.filter.ts @@ -1,10 +1,36 @@ import { ArgumentsHost, Catch } from '@nestjs/common'; import { AbstractHttpAdapter, BaseExceptionFilter } from '@nestjs/core'; import { GqlArgumentsHost, GqlContextType } from '@nestjs/graphql'; +import { + PrismaClientInitializationError, + PrismaClientKnownRequestError, + PrismaClientRustPanicError, + PrismaClientUnknownRequestError, + PrismaClientValidationError, +} from '@prisma/client/runtime/library'; import { isAppError } from '@snipcode/utils'; import { Response } from 'express'; import { GraphQLError } from 'graphql'; +import { INTERNAL_SERVER_ERROR } from '../utils/constants'; + +type PrismaError = + | PrismaClientInitializationError + | PrismaClientKnownRequestError + | PrismaClientRustPanicError + | PrismaClientUnknownRequestError + | PrismaClientValidationError; + +const isPrismaError = (error: unknown): error is PrismaError => { + return ( + error instanceof PrismaClientInitializationError || + error instanceof PrismaClientKnownRequestError || + error instanceof PrismaClientRustPanicError || + error instanceof PrismaClientUnknownRequestError || + error instanceof PrismaClientValidationError + ); +}; + @Catch() export class ApplicationExceptionFilter extends BaseExceptionFilter { constructor(httpAdapter: AbstractHttpAdapter) { @@ -22,18 +48,31 @@ export class ApplicationExceptionFilter extends BaseExceptionFilter { }, originalError: exception, }); + } else if (isPrismaError(exception)) { + throw new GraphQLError(INTERNAL_SERVER_ERROR, { + extensions: { + code: 'DATABASE_ERROR', + }, + }); } } else { - if (isAppError(exception)) { - const ctx = host.switchToHttp(); - const response = ctx.getResponse(); + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + if (isAppError(exception)) { response.status(400).json({ code: exception.code, message: exception.message, timestamp: new Date().toISOString(), }); + } else if (isPrismaError(exception)) { + response.status(500).json({ + code: 'DATABASE_ERROR', + message: INTERNAL_SERVER_ERROR, + timestamp: new Date().toISOString(), + }); } + super.catch(exception, host); } } diff --git a/apps/backend/src/utils/constants.ts b/apps/backend/src/utils/constants.ts index aeff5b03..43c066f5 100644 --- a/apps/backend/src/utils/constants.ts +++ b/apps/backend/src/utils/constants.ts @@ -11,3 +11,5 @@ export const AUTH_USER_NOT_FOUND_CODE = 'AUTH_USER_NOT_FOUND'; export const AUTH_SUCCESS_URL = (webAuthSuccessUrl: string, sessionToken: string): string => { return `${webAuthSuccessUrl}?token=${sessionToken}`; }; + +export const INTERNAL_SERVER_ERROR = 'An internal error occurred, please try again later.';