Skip to content

Commit

Permalink
support custom error message mappings (#73)
Browse files Browse the repository at this point in the history
* add option to modify error messages, closes #72

* refactor

* avoid duplicate definitions for the error codes

* Update lib/prisma-client-exception.filter.ts

---------

Co-authored-by: Marc <[email protected]>
  • Loading branch information
megane42 and marcjulian authored Nov 1, 2023
1 parent 50866eb commit a1988b1
Showing 1 changed file with 64 additions and 19 deletions.
83 changes: 64 additions & 19 deletions lib/prisma-client-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
};

/**
Expand All @@ -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);

Expand All @@ -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;
}

/**
Expand All @@ -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);
}

Expand All @@ -87,20 +101,51 @@ export class PrismaClientExceptionFilter extends BaseExceptionFilter {
);
} else if (host.getType<GqlContextType>() === 'graphql') {
// for graphql requests
if (!Object.keys(this.errorCodesStatusMapping).includes(exception.code)) {
if (statusCode === undefined) {
return exception;
}

return new HttpException({ statusCode, message }, statusCode);
}
}

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()
);
}
}

Expand Down

0 comments on commit a1988b1

Please sign in to comment.