Skip to content

Commit

Permalink
feat: improved isErrorEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
Yehonal committed Sep 25, 2024
1 parent d269dc8 commit 9a7efbd
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 9 deletions.
25 changes: 24 additions & 1 deletion event-manager/src/__tests__/event.helper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,33 @@ describe('EventHelper', () => {
});

it('should return true if the event is an error event', () => {
class CustomBadRequestException {
getStatus() {
return HttpStatus.BAD_REQUEST;
}
}

class CustomInternalServerErrorException {
getStatus() {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}

expect(isErrorEvent({})).toBeFalsy();
expect(isErrorEvent({ errorClass: true })).toBeTruthy();
expect(isErrorEvent({ errorClass: DefaultError })).toBeTruthy();
expect(isErrorEvent({ errorClass: HttpException })).toBeFalsy();
expect(isErrorEvent({ errorClass: HttpException })).toBeTruthy();
expect(isErrorEvent({ errorClass: Error })).toBeTruthy();
expect(isErrorEvent({ errorClass: CustomBadRequestException })).toBeFalsy();
expect(
isErrorEvent({ errorClass: CustomInternalServerErrorException }),
).toBeTruthy();
expect(
isErrorEvent({ errorClass: new CustomBadRequestException() }),
).toBeFalsy();
expect(
isErrorEvent({ errorClass: new CustomInternalServerErrorException() }),
).toBeTruthy();
expect(
isErrorEvent({
errorClass: new HttpException('test', HttpStatus.BAD_REQUEST),
Expand Down
33 changes: 27 additions & 6 deletions event-manager/src/event.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isClass } from '@nestjs-yalc/utils/class.helper.js';
import { HttpStatus } from '@nestjs/common';
import { LogLevel } from 'typeorm';
import { IErrorEventOptions } from './event.js';
import { getStatusCodeFromError } from '@nestjs-yalc/utils/http.helper.js';

export function getLogLevelByStatus(statusCode: number) {
let loggerLevel: LogLevel;
Expand Down Expand Up @@ -38,12 +39,32 @@ export function isErrorEvent(options: IErrorEventOptions) {
return false;
}

if (options.errorClass === true) {
return true;
}

if (isClass(options.errorClass, DefaultError.name)) {
return true;
}

const statusCode = getStatusCodeFromError(options.errorClass);
if (statusCode) {
return getLogLevelByStatus(statusCode) === LogLevelEnum.ERROR;
}

/**
* This is a fallback to handle edge cases but it's slower since
* it creates an instance of the error class and should not happen
*/
let error;
if (isClass(options.errorClass)) {
error = new options.errorClass();
} else {
error = options.errorClass;
}

return (
options.errorClass === true ||
isClass(options.errorClass, DefaultError.name) ||
(!isClass(options.errorClass) &&
options.errorClass.getStatus &&
getLogLevelByStatus(options.errorClass.getStatus()) ===
LogLevelEnum.ERROR)
!error.getStatus ||
getLogLevelByStatus(error.getStatus()) === LogLevelEnum.ERROR
);
}
16 changes: 15 additions & 1 deletion utils/src/__tests__/http.helper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { describe, expect, it } from '@jest/globals';

import { getHttpStatusDescription } from '../http.helper.js';
import {
getHttpStatusDescription,
getStatusCodeFromError,
} from '../http.helper.js';
import { BadRequestException, HttpStatus } from '@nestjs/common';

describe('Test http.helper.ts', () => {
it('should run getHttpStatusDescription', () => {
Expand All @@ -12,4 +16,14 @@ describe('Test http.helper.ts', () => {
it('should work with the fallback', () => {
expect(getHttpStatusDescription(999)).toBe('Unknown status code');
});

it('should run getStatusCodeFromError', () => {
expect(getStatusCodeFromError(BadRequestException)).toBe(
HttpStatus.BAD_REQUEST,
);
});

it('should work with the fallback', () => {
expect(getStatusCodeFromError(999)).toBe(null);
});
});
62 changes: 61 additions & 1 deletion utils/src/http.helper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
import { HttpStatus } from '@nestjs/common';
import { ClassType } from '@nestjs-yalc/types/globals.js';
import {
BadGatewayException,
BadRequestException,
ConflictException,
ForbiddenException,
GatewayTimeoutException,
GoneException,
HttpException,
HttpStatus,
InternalServerErrorException,
MethodNotAllowedException,
MisdirectedException,
NotAcceptableException,
NotFoundException,
NotImplementedException,
PayloadTooLargeException,
PreconditionFailedException,
RequestTimeoutException,
ServiceUnavailableException,
UnauthorizedException,
UnprocessableEntityException,
UnsupportedMediaTypeException,
} from '@nestjs/common';
import { HttpStatusCode } from 'axios';
import { isClass } from './class.helper.js';

export const HttpStatusCodes = {
...HttpStatus,
Expand Down Expand Up @@ -104,3 +128,39 @@ export const getHttpStatusDescription = (
): string => {
return httpStatusDescriptions[status] ?? fallbackDescription;
};

const httpExceptionStatusCodes = {
[BadRequestException.name]: HttpStatus.BAD_REQUEST,
[UnauthorizedException.name]: HttpStatus.UNAUTHORIZED,
[ForbiddenException.name]: HttpStatus.FORBIDDEN,
[NotFoundException.name]: HttpStatus.NOT_FOUND,
[MethodNotAllowedException.name]: HttpStatus.METHOD_NOT_ALLOWED,
[NotAcceptableException.name]: HttpStatus.NOT_ACCEPTABLE,
[RequestTimeoutException.name]: HttpStatus.REQUEST_TIMEOUT,
[ConflictException.name]: HttpStatus.CONFLICT,
[GoneException.name]: HttpStatus.GONE,
[PreconditionFailedException.name]: HttpStatus.PRECONDITION_FAILED,
[PayloadTooLargeException.name]: HttpStatus.PAYLOAD_TOO_LARGE,
[UnsupportedMediaTypeException.name]: HttpStatus.UNSUPPORTED_MEDIA_TYPE,
[UnprocessableEntityException.name]: HttpStatus.UNPROCESSABLE_ENTITY,
[InternalServerErrorException.name]: HttpStatus.INTERNAL_SERVER_ERROR,
[NotImplementedException.name]: HttpStatus.NOT_IMPLEMENTED,
[BadGatewayException.name]: HttpStatus.BAD_GATEWAY,
[ServiceUnavailableException.name]: HttpStatus.SERVICE_UNAVAILABLE,
[GatewayTimeoutException.name]: HttpStatus.GATEWAY_TIMEOUT,
[HttpException.name]: HttpStatus.INTERNAL_SERVER_ERROR,
[MisdirectedException.name]: HttpStatus.MISDIRECTED,
};

/**
* Function to convert all HttpException based errors classes to their corresponding status code
* using a predefined list of status codes
*/
export function getStatusCodeFromError(error: ClassType<any> | any) {
if (!isClass(error) && error.getStatus) {
return error.getStatus();
}

const errorName = error.name;
return httpExceptionStatusCodes[errorName] || null;
}

0 comments on commit 9a7efbd

Please sign in to comment.