Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I handle TypeORM error in NestJS?

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
    }
  }
}
like image 680
JeffMinsungKim Avatar asked Nov 22 '19 11:11

JeffMinsungKim


People also ask

What is API with nestjs?

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.

What is typeorm in Node JS?

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..

How does nestjs handle database migrations?

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.

What is the default exception filter in nestjs?

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.


Video Answer


2 Answers

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)
like image 132
Kim Kern Avatar answered Sep 18 '22 07:09

Kim Kern


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';
like image 40
Panayiotis Hiripis Avatar answered Sep 18 '22 07:09

Panayiotis Hiripis