Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d165795

Browse files
committedApr 10, 2019
feature(grpc): add grpc exception filter
1 parent 09df23d commit d165795

File tree

5 files changed

+90
-9
lines changed

5 files changed

+90
-9
lines changed
 

‎integration/microservices/e2e/sum-grpc.spec.ts

+10
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ describe('GRPC transport', () => {
3535
.expect(200, { result: 15 });
3636
});
3737

38+
it(`handle exception correctly`, () => {
39+
return (
40+
request(server)
41+
.post('/divide')
42+
.send({ first: 42, last: 0 })
43+
// TODO: this will change once the grpc client raise the closest HTTP exception to OutOfBound
44+
.expect(500, { message: 'Dividing by 0 is Strictly Forbidden' })
45+
);
46+
});
47+
3848
afterEach(async () => {
3949
await app.close();
4050
});

‎integration/microservices/src/grpc/grpc.controller.ts

+32-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
import { Body, Controller, HttpCode, Post } from '@nestjs/common';
2-
import { Client, ClientGrpc, GrpcMethod, Transport } from '@nestjs/microservices';
1+
import { Body, Controller, HttpCode, Post, UseFilters } from '@nestjs/common';
2+
import {
3+
Client,
4+
ClientGrpc,
5+
GrpcMethod,
6+
Transport,
7+
GrpcOutOfRangeException,
8+
GrpcExceptionFilter,
9+
} from '@nestjs/microservices';
310
import { join } from 'path';
411
import { Observable, of } from 'rxjs';
512

13+
interface DivideParams {
14+
first: number;
15+
last: number;
16+
}
17+
618
@Controller()
719
export class GrpcController {
820
@Client({
@@ -16,7 +28,7 @@ export class GrpcController {
1628

1729
@Post()
1830
@HttpCode(200)
19-
call(@Body() data: number[]): Observable<number> {
31+
sumHttp(@Body() data: number[]): Observable<number> {
2032
const svc = this.client.getService<any>('Math');
2133
return svc.sum({ data });
2234
}
@@ -27,4 +39,21 @@ export class GrpcController {
2739
result: data.reduce((a, b) => a + b),
2840
});
2941
}
42+
43+
@Post('/divide')
44+
@HttpCode(200)
45+
divideHttp(@Body() { first, last }: DivideParams): Observable<number> {
46+
const svc = this.client.getService<any>('Math');
47+
return svc.sum({ first, last });
48+
}
49+
50+
@UseFilters(new GrpcExceptionFilter())
51+
@GrpcMethod('Math')
52+
async divide({ first, last }: DivideParams): Promise<any> {
53+
const result = first / last;
54+
if (!isFinite(result)) {
55+
throw new GrpcOutOfRangeException('Dividing by 0 is Strictly Forbidden');
56+
}
57+
return result;
58+
}
3059
}

‎integration/microservices/src/grpc/math.proto

+10-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ syntax = "proto3";
33
package math;
44

55
service Math {
6-
rpc Sum (RequestSum) returns (SumResult) {}
6+
rpc Sum(RequestSum) returns (SumResult) {}
7+
rpc Divide(RequestDivide) returns (DivideResult) {}
78
}
89

9-
message SumResult {
10-
int32 result = 1;
11-
}
10+
message SumResult { int32 result = 1; }
11+
12+
message RequestSum { repeated int32 data = 1; }
13+
14+
message DivideResult { int32 result = 1; }
1215

13-
message RequestSum {
14-
repeated int32 data = 1;
16+
message RequestDivide {
17+
int32 first = 1;
18+
int32 last = 2;
1519
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import {
2+
Logger,
3+
RpcExceptionFilter,
4+
ArgumentsHost,
5+
Catch,
6+
} from '@nestjs/common';
7+
import { isError, isObject } from '@nestjs/common/utils/shared.utils';
8+
import { MESSAGES } from '@nestjs/core/constants';
9+
10+
import { Observable, throwError } from 'rxjs';
11+
12+
import { GrpcException } from './grpc-exceptions';
13+
import { GrpcStatus } from 'enums/grpc-status.enum';
14+
15+
@Catch()
16+
export class GrpcExceptionFilter<T = any, R = any>
17+
implements RpcExceptionFilter<T> {
18+
private static readonly logger = new Logger('GrpcExceptionsHandler');
19+
20+
catch(exception: T, host: ArgumentsHost): Observable<R> {
21+
if (!(exception instanceof GrpcException)) {
22+
const errorMessage = MESSAGES.UNKNOWN_EXCEPTION_MESSAGE;
23+
const loggerArgs = isError(exception)
24+
? [exception.message, exception.stack]
25+
: [exception];
26+
27+
const logger = GrpcExceptionFilter.logger;
28+
logger.error.apply(logger, loggerArgs as any);
29+
30+
return throwError({ code: GrpcStatus.UNKNOWN, message: errorMessage });
31+
}
32+
const code = exception.getCode();
33+
const error = exception.getError();
34+
const message = isObject(error) ? error : { code, message: error };
35+
return throwError(message);
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './base-rpc-exception-filter';
22
export * from './rpc-exception';
33
export * from './grpc-exceptions';
4+
export * from './grpc-exception-filter';

0 commit comments

Comments
 (0)
Please sign in to comment.