I'd like to create a custom exception filter that handles different kinds of TypeORM errors. I've looked up the TypeORM error classes, and it seems like there's no such thing in TypeORM like MongoError.
I wanted to make something similar to 1FpGLLjZSZMx6k's answer, and here's what I've done so far.
import { QueryFailedError } from 'typeorm';
@Catch(QueryFailedError)
export class QueryFailedExceptionFilter implements ExceptionFilter {
catch(exception: QueryFailedError, host: ArgumentsHost) {
const context = host.switchToHttp();
const response = context.getResponse<Response>();
const request = context.getRequest<Request>();
const { url } = request;
const { name } = exception;
const errorResponse = {
path: url,
timestamp: new Date().toISOString(),
message: name,
};
response.status(HttpStatus.BAD_REQUEST).json(errorResponse);
}
}
If I need to catch another error for instance, EntityNotFoundError
, I have to write the same code which is a very cumbersome task to do it.
It would be nice if I could handle errors by a single filter like below. Any ideas?
@Catch(TypeORMError)
export class EntityNotFoundExceptionFilter implements ExceptionFilter {
catch(exception: MongoError, host: ArgumentsHost) {
switch (exception.code) {
case some error code:
// handle error
}
}
}
API with NestJS #69. Database migrations with TypeORM NestJS shines when it comes to handling errors and validating data. A lot of that is thanks to using decorators. In this article, we go through features that NestJS provides us with, such as Exception filters and Validation pipes.
In A Nutshell… TypeORM is a type-safe ORM for Node.js and io.js. It provides a simple, intuitive interface for working with your data, and integrates with NEST to provide type safety and autocompletion. In this tutorial, we showed you how to set up TypeORM with a NESTJS project and how to use the two together..
Database migrations with TypeORM NestJS shines when it comes to handling errors and validating data. A lot of that is thanks to using decorators. In this article, we go through features that NestJS provides us with, such as Exception filters and Validation pipes. The code from this series results in this repository.
The default exception filter is called BaseExceptionFilter. We can look into the source code of NestJS and inspect its behavior. // ... // ... // ... // ... Every time there is an error in our application, the catch method runs. There are a few essential things we can get from the above code. Nest expects us to use the HttpException class.
In the documentation, it says:
The
@Catch()
decorator may take a single parameter, or a comma-separated list. This lets you set up the filter for several types of exceptions at once.
So in your case you could write:
@Catch(QueryFailedError, EntityNotFoundError)
To handle different kinds of TypeOrm errors, you can switch / case the exception constructor if it matches any TypeOrm error (from node_modules\typeorm\error). Additionally, the (exception as any).code will provide the actual database error that occured. Notice the @catch() decorator is empty in order to catch all error types.
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from '@nestjs/common';
import { Request, Response } from 'express';
import { QueryFailedError, EntityNotFoundError, CannotCreateEntityIdMapError } from 'typeorm';
import { GlobalResponseError } from './global.response.error';
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
let message = (exception as any).message.message;
let code = 'HttpException';
Logger.error(message, (exception as any).stack, `${request.method} ${request.url}`);
let status = HttpStatus.INTERNAL_SERVER_ERROR;
switch (exception.constructor) {
case HttpException:
status = (exception as HttpException).getStatus();
break;
case QueryFailedError: // this is a TypeOrm error
status = HttpStatus.UNPROCESSABLE_ENTITY
message = (exception as QueryFailedError).message;
code = (exception as any).code;
break;
case EntityNotFoundError: // this is another TypeOrm error
status = HttpStatus.UNPROCESSABLE_ENTITY
message = (exception as EntityNotFoundError).message;
code = (exception as any).code;
break;
case CannotCreateEntityIdMapError: // and another
status = HttpStatus.UNPROCESSABLE_ENTITY
message = (exception as CannotCreateEntityIdMapError).message;
code = (exception as any).code;
break;
default:
status = HttpStatus.INTERNAL_SERVER_ERROR
}
response.status(status).json(GlobalResponseError(status, message, code, request));
}
}
import { Request } from 'express';
import { IResponseError } from './response.error.interface';
export const GlobalResponseError: (statusCode: number, message: string, code: string, request: Request) => IResponseError = (
statusCode: number,
message: string,
code: string,
request: Request
): IResponseError => {
return {
statusCode: statusCode,
message,
code,
timestamp: new Date().toISOString(),
path: request.url,
method: request.method
};
};
export interface IResponseError {
statusCode: number;
message: string;
code: string;
timestamp: string;
path: string;
method: string;
}
Note: As of new version of typeorm
import for EntityNotFoundError
and CannotCreateEntityIdMapError
will be as bellow
import { QueryFailedError } from 'typeorm';
import { EntityNotFoundError } from 'typeorm/error/EntityNotFoundError';
import { CannotCreateEntityIdMapError } from 'typeorm/error/CannotCreateEntityIdMapError';
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With