diff --git a/apps/server/src/core/error/filter/global-error.filter.spec.ts b/apps/server/src/core/error/filter/global-error.filter.spec.ts index 8773c0bb5f3..31ce2b9f04f 100644 --- a/apps/server/src/core/error/filter/global-error.filter.spec.ts +++ b/apps/server/src/core/error/filter/global-error.filter.spec.ts @@ -3,14 +3,14 @@ import { NotFound } from '@feathersjs/errors'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ArgumentsHost, BadRequestException, HttpStatus, InternalServerErrorException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; +import { WsException } from '@nestjs/websockets'; import { BusinessError } from '@shared/common'; import { ErrorLogMessage, Loggable } from '@src/core/logger'; import { Response } from 'express'; -import { WsException } from '@nestjs/websockets'; +import { DomainErrorHandler } from '../domain'; import { ErrorResponse } from '../dto'; import { ErrorUtils } from '../utils'; -import { GlobalErrorFilter } from './global-error.filter'; -import { DomainErrorHandler } from '../domain'; +import { GlobalErrorFilter, UseableContextType } from './global-error.filter'; class SampleBusinessError extends BusinessError { constructor() { @@ -78,19 +78,27 @@ describe('GlobalErrorFilter', () => { describe('catch', () => { describe('when any error is passed as parameter', () => { const setup = () => { - const argumentsHost = createMock(); - argumentsHost.getType.mockReturnValueOnce('http'); + const allContextTypes = Object.keys(UseableContextType); + const contextTypes = [...allContextTypes]; + const argumentsHost = createMock({ + getType: () => contextTypes.pop() || '', + }); const error = new Error('test'); - return { error, argumentsHost }; + return { allContextTypes, argumentsHost, error }; }; - it('should be pass the error to domain error handler', () => { - const { error, argumentsHost } = setup(); + it('should call exec on domain error handler', () => { + const { allContextTypes, argumentsHost, error } = setup(); - service.catch(error, argumentsHost); + allContextTypes.forEach(() => { + service.catch(error, argumentsHost); + }); expect(domainErrorHandler.exec).toBeCalledWith(error); + expect(domainErrorHandler.exec).toBeCalledTimes(allContextTypes.length - 1); + expect(domainErrorHandler.execHttpContext).toBeCalledWith(error, {}); + expect(domainErrorHandler.execHttpContext).toBeCalledTimes(1); }); }); diff --git a/apps/server/src/core/error/filter/global-error.filter.ts b/apps/server/src/core/error/filter/global-error.filter.ts index 5aed86bcf66..7098b49a78b 100644 --- a/apps/server/src/core/error/filter/global-error.filter.ts +++ b/apps/server/src/core/error/filter/global-error.filter.ts @@ -11,7 +11,7 @@ import { ErrorUtils } from '../utils'; // We are receiving rmq instead of rpc and rmq is missing in context type. // @nestjs/common export type ContextType = 'http' | 'ws' | 'rpc'; -enum UseableContextType { +export enum UseableContextType { http = 'http', rpc = 'rpc', ws = 'ws', diff --git a/apps/server/src/shared/common/interceptor/error.interceptor.ts b/apps/server/src/shared/common/interceptor/error.interceptor.ts deleted file mode 100644 index f96cb4be0bd..00000000000 --- a/apps/server/src/shared/common/interceptor/error.interceptor.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { CallHandler, ExecutionContext, HttpStatus, Injectable, NestInterceptor } from '@nestjs/common'; -import { Loggable, Logger, LogMessage, RequestLoggingBody } from '@src/core/logger'; -import { ICurrentUser } from '@src/infra/auth-guard'; -import { Request } from 'express'; -import { catchError, Observable, throwError } from 'rxjs'; -import { BusinessError, ErrorLogMessage, ValidationErrorLogMessage } from '../error'; - -function isLoggableError(error: unknown): error is BusinessError & Loggable { - const isError = error instanceof BusinessError; - const isLoggable = - (error as Loggable).getLogMessage !== undefined && typeof (error as Loggable).getLogMessage === 'function'; - - return isError && isLoggable; -} - -class UnknownLoggableException extends BusinessError implements Loggable { - constructor(private readonly error: unknown, private readonly request: RequestLoggingBody) { - super( - { - type: 'INTERNAL_SERVER_ERROR', - title: 'internal server error', - defaultMessage: 'An internal server error occurred', - }, - HttpStatus.INTERNAL_SERVER_ERROR, - request, - error - ); - } - - public getLogMessage(): LogMessage | ErrorLogMessage | ValidationErrorLogMessage { - return { - message: this.message, - error: this.error as Error, - - data: { - request: this.request, - error: this.error, - }, - }; - } -} - -@Injectable() -export class ErrorInterceptor implements NestInterceptor { - constructor(private readonly logger: Logger) { - this.logger.setContext(ErrorInterceptor.name); - } - - public intercept(context: ExecutionContext, next: CallHandler): Observable { - const request: Request = context.switchToHttp().getRequest(); - const currentUser = request.user as ICurrentUser; - const requestInfo: RequestLoggingBody = { - userId: currentUser.userId, - request: { - url: request.url, - method: request.method, - params: request.params, - query: request.query, - }, - error: undefined, - }; - - return next.handle().pipe( - catchError((error) => { - if (isLoggableError(error)) { - requestInfo.error = error.getLogMessage(); - this.logger.error(error); - - return throwError(() => error); - } - - const exception = new UnknownLoggableException(error, requestInfo); - - requestInfo.error = exception.getLogMessage(); - this.logger.critical(exception); - - return throwError(() => exception); - }) - ); - } -}