Nest.js | Prisma Exception Filter
In Nest.js, you can create an exception filter to handle specific exceptions that may occur in your application. To create an exception filter, you can use the @UseFilters()
decorator and pass in an instance of a class that implements the ExceptionFilter
interface. The class should have a catch()
method that takes in an instance of the exception that was thrown and a ExecutionContext
object.
For example, you can create a class HttpExceptionFilter
that implements the ExceptionFilter
interface:
import { ExceptionFilter, Catch, HttpException } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, context: ExecutionContext) {
// Handle the exception here
}
}
You can then apply the filter globally or on specific controllers or routes using the @UseFilters()
decorator:
@UseFilters(new HttpExceptionFilter())
@Controller()
export class MyController {
// ...
}
or:
@UseFilters(new HttpExceptionFilter())
@Get()
async findAll() {
// ...
}
You can also catch a different type of exception by doing
@Catch(MyException)
export class MyExceptionFilter implements ExceptionFilter {
catch(exception: MyException, context: ExecutionContext) {
// Handle the exception here
}
}
In Nest.js, you can create an exception filter to handle specific exceptions that may occur when using Prisma ORM. To create an exception filter for Prisma, you can use the @UseFilters()
decorator and pass in an instance of a class that implements the ExceptionFilter
interface. The class should have a catch()
method that takes in an instance of the exception that was thrown and a ExecutionContext
object.
For example, you can create a class PrismaExceptionFilter
that implements the ExceptionFilter
interface:
import {
ArgumentsHost,
Catch,
HttpException,
HttpServer,
HttpStatus,
} from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { Prisma } from '@prisma/client';
export type ErrorCodesStatusMapping = {
[key: string]: number;
};
/**
* {@link PrismaClientExceptionFilter}
* catches {@link Prisma.PrismaClientKnownRequestError}
* and {@link Prisma.NotFoundError} exceptions.
*/
@Catch(Prisma?.PrismaClientKnownRequestError, Prisma?.NotFoundError)
export class PrismaClientExceptionFilter extends BaseExceptionFilter {
/**
* default error codes mapping
*
* 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 = {
P2000: HttpStatus.BAD_REQUEST,
P2002: HttpStatus.CONFLICT,
P2025: HttpStatus.NOT_FOUND,
};
/**
* @param applicationRef
* @param errorCodesStatusMapping
*/
constructor(
applicationRef?: HttpServer,
errorCodesStatusMapping?: ErrorCodesStatusMapping,
) {
super(applicationRef);
if (errorCodesStatusMapping) {
this.errorCodesStatusMapping = Object.assign(
this.errorCodesStatusMapping,
errorCodesStatusMapping,
);
}
}
/**
* @param exception
* @param host
* @returns
*/
catch(
exception: Prisma.PrismaClientKnownRequestError | Prisma.NotFoundError | any,
host: ArgumentsHost,
) {
if (exception instanceof Prisma.PrismaClientKnownRequestError) {
return this.catchClientKnownRequestError(exception, host);
}
if (exception instanceof Prisma.NotFoundError) {
return this.catchNotFoundError(exception, host);
}
}
private catchClientKnownRequestError(
exception: Prisma.PrismaClientKnownRequestError,
host: ArgumentsHost,
) {
const statusCode = this.errorCodesStatusMapping[exception.code];
const message = `[${exception.code}]: ${this.exceptionShortMessage(exception.message)}`;
if (!Object.keys(this.errorCodesStatusMapping).includes(exception.code)) {
return super.catch(exception, host);
}
super.catch(new HttpException({ statusCode, message }, statusCode), host);
}
private catchNotFoundError(
{ message }: Prisma.NotFoundError,
host: ArgumentsHost,
) {
const statusCode = HttpStatus.NOT_FOUND;
super.catch(new HttpException({ statusCode, message }, statusCode), host);
}
private exceptionShortMessage(message: string): string {
const shortMessage = message.substring(message.indexOf('→'));
return shortMessage
.substring(shortMessage.indexOf('\n'))
.replace(/\n/g, '')
.trim();
}
Change main.js
:
{
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(
new AllExceptionsFilter(),
new PrismaClientExceptionFilter(httpAdapter),
);
}
or:
{
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter, {
P2022: HttpStatus.BAD_REQUEST,
}));
}
If you have any questions or feedback about this article, feel free to leave a comment.
Member discussion