Advertisement
aldikhan13

nestjs error capture handling

May 13th, 2025
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 6.91 KB | Source Code | 0 0
  1. import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus as status } from '@nestjs/common'
  2. import { HttpArgumentsHost } from '@nestjs/common/interfaces'
  3. import { OutgoingMessage } from 'node:http'
  4. import { HttpAdapterHost } from '@nestjs/core'
  5. import { Request, Response } from 'express'
  6. import moment from 'moment-timezone'
  7.  
  8. import { Logger } from '~/infrastructure/common/helpers/logger.helper'
  9. import { ELoggerType } from '~/domain/enums/common.enum'
  10. import { response } from '~/infrastructure/common/helpers/response.helper'
  11. import { IResponseInfo } from './domain/interfaces/common.interface'
  12.  
  13. interface ErrorDetails {
  14.   statCode: number
  15.   errCode: string
  16.   errMessage: string
  17.   errors: any[]
  18. }
  19.  
  20. @Catch()
  21. export class AppErrorException implements ExceptionFilter {
  22.   private readonly defaultErrorCodes: Record<number, { errCode: string; errMessage?: string }> = {
  23.     [status.INTERNAL_SERVER_ERROR]: { errCode: 'GENERAL_ERROR', errMessage: 'Application is busy, please try again later!' },
  24.     [status.BAD_GATEWAY]: { errCode: 'SERVICE_ERROR', errMessage: 'Application is busy, please try again later!' },
  25.     [status.SERVICE_UNAVAILABLE]: { errCode: 'SERVICE_UNAVAILABLE', errMessage: 'Application is not available, please try again later!' },
  26.     [status.GATEWAY_TIMEOUT]: { errCode: 'SERVICE_TIMEOUT', errMessage: 'Application is timeout, please try again later!' },
  27.     [status.CONFLICT]: { errCode: 'DUPLICATE_RESOURCE' },
  28.     [status.UNPROCESSABLE_ENTITY]: { errCode: 'INVALID_REQUEST' },
  29.     [status.PRECONDITION_FAILED]: { errCode: 'REQUEST_COULD_NOT_BE_PROCESSED' },
  30.     [status.FORBIDDEN]: { errCode: 'ACCESS_DENIED' },
  31.     [status.UNAUTHORIZED]: { errCode: 'UNAUTHORIZED_TOKEN' },
  32.     [status.NOT_FOUND]: { errCode: 'UNKNOWN_RESOURCE' },
  33.   }
  34.  
  35.   constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
  36.  
  37.   private logError(exception: any): void {
  38.     const name = 'ApplicationError'
  39.     const type = ELoggerType.ERROR
  40.     let message = ''
  41.  
  42.     if (exception instanceof HttpException) {
  43.       message = `
  44.         ====================================================
  45.         ======== ${name} [HttpException] =========
  46.         ====================================================
  47.  
  48.           name: ${exception.name}
  49.           code: ${exception.getStatus()}
  50.           message: ${exception.message}
  51.           response: ${JSON.stringify(exception.getResponse())}
  52.           stack: ${exception.stack}
  53.  
  54.         ====================================================
  55.         ====================================================
  56.         ====================================================
  57.       `
  58.     } else if (exception instanceof Error) {
  59.       message = `
  60.         ============================================
  61.         ======== ${name} [Error] =========
  62.         ============================================
  63.  
  64.           name: ${exception.name}
  65.           message: ${exception.message}
  66.           stack: ${exception.stack}
  67.  
  68.         ============================================
  69.         ============================================
  70.         ============================================
  71.       `
  72.     } else {
  73.       message = `
  74.         =============================================
  75.         ======== ${name} [Common] =========
  76.         =============================================
  77.  
  78.           name: ${exception.name}
  79.           message: ${exception.message}
  80.           response: ${JSON.stringify(exception)}
  81.           stack: ${exception.stack}
  82.  
  83.         =============================================
  84.         =============================================
  85.         =============================================
  86.       `
  87.     }
  88.  
  89.     Logger.log(name, type, message, exception)
  90.   }
  91.  
  92.   private getErrorDetails(exception: any): ErrorDetails {
  93.     let statCode: number = status.INTERNAL_SERVER_ERROR
  94.     let errMessage: string = ''
  95.     let errors: any[] = []
  96.  
  97.     if (exception instanceof HttpException) {
  98.       statCode = exception.getStatus()
  99.       const response: any = exception.getResponse()
  100.  
  101.       if (typeof response === 'string') {
  102.         errMessage = response
  103.       } else if (response && typeof response === 'object') {
  104.         if (response?.message) {
  105.           errMessage = response?.message
  106.         } else if (response?.error) {
  107.           errMessage = response?.error
  108.         }
  109.  
  110.         if (Array.isArray(response?.errors)) {
  111.           errors = response?.errors
  112.         }
  113.       }
  114.     } else if (exception instanceof Error) {
  115.       errMessage = exception.message
  116.     } else {
  117.       if (exception.stat_code) {
  118.         statCode = exception.stat_code
  119.       }
  120.  
  121.       if (exception.error) {
  122.         errMessage = exception.error
  123.       } else if (exception.errors) {
  124.         errors = exception.errors
  125.       }
  126.     }
  127.  
  128.     if (statCode === status.BAD_REQUEST) {
  129.       statCode = status.UNPROCESSABLE_ENTITY
  130.     } else if (statCode === status.FAILED_DEPENDENCY) {
  131.       statCode = status.INTERNAL_SERVER_ERROR
  132.     }
  133.  
  134.     const defaultError: Record<string, any> = this.defaultErrorCodes[statCode]
  135.     const errCode: string = defaultError ? defaultError?.errCode : 'GENERAL_ERROR'
  136.  
  137.     if (defaultError && defaultError.errMessage && !errMessage) {
  138.       errMessage = defaultError.errMessage
  139.     }
  140.  
  141.     if (!errMessage && errors?.length === 0) {
  142.       errMessage = 'An error occurred'
  143.     }
  144.  
  145.     return { statCode, errCode, errMessage, errors }
  146.   }
  147.  
  148.   private setHeader(req: Request, res: Response): void {
  149.     const clientIpReq: string = req.header('X-Forwarded-For') || req.header('X-Real-IP') || req.header('X-Client-IP') || req.ip || req.socket.remoteAddress
  150.     const serverDateTimeReq: string = moment(new Date()).format()
  151.  
  152.     res.set('X-Request-ID', req.header('X-Request-ID'))
  153.     res.set('X-Client-IP', clientIpReq)
  154.     res.set('X-Server-Time', serverDateTimeReq)
  155.   }
  156.  
  157.   catch(exception: HttpException, host: ArgumentsHost): OutgoingMessage {
  158.     const args: HttpArgumentsHost = host.switchToHttp()
  159.     const req: Request = args.getRequest()
  160.     const res: Response = args.getResponse()
  161.  
  162.     this.logError(exception)
  163.     const { statCode, errCode, errMessage, errors } = this.getErrorDetails(exception)
  164.     this.setHeader(req, res)
  165.  
  166.     const timestamp: string = moment(new Date()).format()
  167.     const startTime: number = Number(req['startTime']) || Date.now()
  168.     const serverInfo: IResponseInfo = {
  169.       host: req.hostname,
  170.       protocol: req.protocol,
  171.       path: req.path,
  172.       method: req.method,
  173.       timestamp: timestamp,
  174.       response_time: `${Date.now() - startTime} ms`,
  175.     }
  176.  
  177.     const { httpAdapter }: HttpAdapterHost = this.httpAdapterHost
  178.     if (errors.length > 0) {
  179.       return httpAdapter.reply(res, response({ stat_code: statCode, err_code: errCode, errors, info: serverInfo }), statCode)
  180.     } else {
  181.       return httpAdapter.reply(res, response({ stat_code: statCode, err_code: errCode, error: errMessage, info: serverInfo }), statCode)
  182.     }
  183.   }
  184. }
  185.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement