diff --git a/lib/prisma-client-exception.filter.ts b/lib/prisma-client-exception.filter.ts index bc97e87..1a0dae4 100644 --- a/lib/prisma-client-exception.filter.ts +++ b/lib/prisma-client-exception.filter.ts @@ -12,7 +12,12 @@ import { Prisma } from '@prisma/client'; export declare type GqlContextType = 'graphql' | ContextType; export type ErrorCodesStatusMapping = { - [key: string]: number; + [key: string]: + | number + | { + statusCode?: number; + errorMessage?: string; + }; }; /** @@ -26,19 +31,21 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter { * Error codes definition for Prisma Client (Query Engine) * @see https://www.prisma.io/docs/reference/api-reference/error-reference#prisma-client-query-engine */ - private errorCodesStatusMapping: ErrorCodesStatusMapping = { + private readonly defaultMapping = { P2000: HttpStatus.BAD_REQUEST, P2002: HttpStatus.CONFLICT, P2025: HttpStatus.NOT_FOUND, }; + private readonly userDefinedMapping?: ErrorCodesStatusMapping; + /** * @param applicationRef * @param errorCodesStatusMapping */ constructor( applicationRef?: HttpServer, - errorCodesStatusMapping: ErrorCodesStatusMapping | null = null, + errorCodesStatusMapping?: ErrorCodesStatusMapping, ) { super(applicationRef); @@ -51,12 +58,15 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter { // P2022: HttpStatus.BAD_REQUEST, // })); // - if (errorCodesStatusMapping) { - this.errorCodesStatusMapping = Object.assign( - this.errorCodesStatusMapping, - errorCodesStatusMapping, - ); - } + // or + // + // const { httpAdapter } = app.get(HttpAdapterHost); + // app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter, { + // // You can omit either statusCode or errorMessage so that the default one is used. + // P2022: { statusCode: HttpStatus.BAD_REQUEST, errorMessage: "bad request" }, + // })); + // + this.userDefinedMapping = errorCodesStatusMapping; } /** @@ -72,12 +82,16 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter { exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost, ) { - const statusCode = this.errorCodesStatusMapping[exception.code]; + const statusCode = + this.userDefinedStatusCode(exception) || + this.defaultStatusCode(exception); + const message = - `[${exception.code}]: ` + this.exceptionShortMessage(exception.message); + this.userDefinedExceptionMessage(exception) || + this.defaultExceptionMessage(exception); if (host.getType() === 'http') { - if (!Object.keys(this.errorCodesStatusMapping).includes(exception.code)) { + if (statusCode === undefined) { return super.catch(exception, host); } @@ -87,7 +101,7 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter { ); } else if (host.getType() === 'graphql') { // for graphql requests - if (!Object.keys(this.errorCodesStatusMapping).includes(exception.code)) { + if (statusCode === undefined) { return exception; } @@ -95,12 +109,43 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter { } } - private exceptionShortMessage(message: string): string { - const shortMessage = message.substring(message.indexOf('→')); - return shortMessage - .substring(shortMessage.indexOf('\n')) - .replace(/\n/g, '') - .trim(); + private userDefinedStatusCode( + exception: Prisma.PrismaClientKnownRequestError, + ): number | undefined { + const userDefinedValue = this.userDefinedMapping?.[exception.code]; + return typeof userDefinedValue === 'number' + ? userDefinedValue + : userDefinedValue?.statusCode; + } + + private defaultStatusCode( + exception: Prisma.PrismaClientKnownRequestError, + ): number | undefined { + return this.defaultMapping[exception.code]; + } + + private userDefinedExceptionMessage( + exception: Prisma.PrismaClientKnownRequestError, + ): string | undefined { + const userDefinedValue = this.userDefinedMapping?.[exception.code]; + return typeof userDefinedValue === 'number' + ? undefined + : userDefinedValue?.errorMessage; + } + + private defaultExceptionMessage( + exception: Prisma.PrismaClientKnownRequestError, + ): string { + const shortMessage = exception.message.substring( + exception.message.indexOf('→'), + ); + return ( + `[${exception.code}]: ` + + shortMessage + .substring(shortMessage.indexOf('\n')) + .replace(/\n/g, '') + .trim() + ); } }