Skip to content

Commit

Permalink
Merge pull request #1 from harrylowkey/feat/grpc-exception-filter
Browse files Browse the repository at this point in the history
feat: grpc exception filter
  • Loading branch information
dung-nguyentien authored Aug 8, 2023
2 parents 11af1cd + ad64690 commit 2c840d4
Show file tree
Hide file tree
Showing 9 changed files with 2,821 additions and 2,534 deletions.
30 changes: 30 additions & 0 deletions libs/constants/grpc_status_code_mapping.constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { HttpStatus } from '@nestjs/common';
import { status } from '@grpc/grpc-js';

export const HTTP_STATUS_CODE: Record<number, number> = {
// standard gRPC error mapping
// https://cloud.google.com/apis/design/errors#handling_errors
[HttpStatus.BAD_REQUEST]: status.INVALID_ARGUMENT,
[HttpStatus.UNAUTHORIZED]: status.UNAUTHENTICATED,
[HttpStatus.FORBIDDEN]: status.PERMISSION_DENIED,
[HttpStatus.NOT_FOUND]: status.NOT_FOUND,
[HttpStatus.CONFLICT]: status.ALREADY_EXISTS,
[HttpStatus.GONE]: status.ABORTED,
[HttpStatus.TOO_MANY_REQUESTS]: status.RESOURCE_EXHAUSTED,
499: status.CANCELLED,
[HttpStatus.INTERNAL_SERVER_ERROR]: status.INTERNAL,
[HttpStatus.NOT_IMPLEMENTED]: status.UNIMPLEMENTED,
[HttpStatus.BAD_GATEWAY]: status.UNKNOWN,
[HttpStatus.SERVICE_UNAVAILABLE]: status.UNAVAILABLE,
[HttpStatus.GATEWAY_TIMEOUT]: status.DEADLINE_EXCEEDED,

// additional built-in http exceptions
// https://docs.nestjs.com/exception-filters#built-in-http-exceptions
[HttpStatus.HTTP_VERSION_NOT_SUPPORTED]: status.UNAVAILABLE,
[HttpStatus.PAYLOAD_TOO_LARGE]: status.OUT_OF_RANGE,
[HttpStatus.UNSUPPORTED_MEDIA_TYPE]: status.CANCELLED,
[HttpStatus.UNPROCESSABLE_ENTITY]: status.CANCELLED,
[HttpStatus.I_AM_A_TEAPOT]: status.UNKNOWN,
[HttpStatus.METHOD_NOT_ALLOWED]: status.CANCELLED,
[HttpStatus.PRECONDITION_FAILED]: status.FAILED_PRECONDITION
};
19 changes: 19 additions & 0 deletions libs/enums/grpc-status.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export enum GrpcStatusEnum {
OK = 0,
CANCELLED = 1,
UNKNOWN = 2,
INVALID_ARGUMENT = 3,
DEADLINE_EXCEEDED = 4,
NOT_FOUND = 5,
ALREADY_EXISTS = 6,
PERMISSION_DENIED = 7,
RESOURCE_EXHAUSTED = 8,
FAILED_PRECONDITION = 9,
ABORTED = 10,
OUT_OF_RANGE = 11,
UNIMPLEMENTED = 12,
INTERNAL = 13,
UNAVAILABLE = 14,
DATA_LOSS = 15,
UNAUTHENTICATED = 16
}
11 changes: 10 additions & 1 deletion libs/filters/base-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { ArgumentsHost } from '@nestjs/common';
import { throwError } from 'rxjs';
import { status } from '@grpc/grpc-js';
import { HTTP_STATUS_CODE } from '../constants/grpc_status_code_mapping.constant';

export abstract class BaseExceptionFilter {
protected isMicroservice: boolean = false;
protected isGrpc: boolean = false;

protected getLanguage(host: ArgumentsHost) {
return host.switchToHttp().getRequest().i18nLang;
}

protected responseError(host: ArgumentsHost, code, message, errors = null) {
if (this.isMicroservice) {
if (this.isGrpc) {
return throwError(() => ({
message: message,
details: errors.message[0],
code: HTTP_STATUS_CODE[code] ?? status.UNKNOWN
}));
} else if (this.isMicroservice) {
return throwError(() =>
JSON.stringify({
message: message,
Expand Down
10 changes: 10 additions & 0 deletions libs/filters/grpc-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Catch } from '@nestjs/common';
import { HttpExceptionFilter } from './http-exception.filter';

@Catch()
export class GrpcExceptionFilter extends HttpExceptionFilter {
constructor() {
super();
this.isGrpc = true;
}
}
3 changes: 2 additions & 1 deletion libs/filters/http-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { trans } from '@hodfords/nestjs-cls-translation';
@Catch()
export class HttpExceptionFilter extends BaseExceptionFilter implements ExceptionFilter {
protected isMicroservice: boolean = false;
protected isGrpc: boolean = false;

catch(exception, host: ArgumentsHost) {
let language = this.getLanguage(host);
Expand All @@ -28,7 +29,7 @@ export class HttpExceptionFilter extends BaseExceptionFilter implements Exceptio
};
return this.catchBadRequestWithArgs(host, 'error.field_malformed', language, args);
} else if (exception instanceof ValidateException) {
return new ValidatorExceptionFilter(this.isMicroservice).catch(exception, host);
return new ValidatorExceptionFilter(this.isMicroservice, this.isGrpc).catch(exception, host);
} else if (exception instanceof PayloadTooLargeException) {
return this.catchPayloadTooLargeException(host, 'error.multer.file_too_large', language);
} else if (exception.type === 'entity.too.large') {
Expand Down
3 changes: 2 additions & 1 deletion libs/filters/validator-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { trans } from '@hodfords/nestjs-cls-translation';

@Catch()
export class ValidatorExceptionFilter extends BaseExceptionFilter implements ExceptionFilter {
constructor(isMicroservice: boolean) {
constructor(isMicroservice: boolean, isGrpc: boolean) {
super();
this.isMicroservice = isMicroservice;
this.isGrpc = isGrpc;
}

catch(exception: ValidateException, host: ArgumentsHost) {
Expand Down
2 changes: 2 additions & 0 deletions libs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export * from './filters/base-exception.filter';
export * from './filters/http-exception.filter';
export * from './filters/microservice-exception.filter';
export * from './filters/validator-exception.filter';
export * from './filters/grpc-exception.filter';
export * from './interfaces/validation-error.interface';
export * from './types/validation-error-exception.type';
export * from './types/validation-error-exception-detail.type';
export * from './types/validation-error-exception-message.type';
export * from './enums/grpc-status.enum';
Loading

0 comments on commit 2c840d4

Please sign in to comment.