-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
gRPC exceptions and filter #1953
Description
After discussion the goal is to implement gRPC exceptions and filter, and document it, to improve gRPC integration.
See #1953 (comment)
-- OLD ISSUE --
I'm submitting a...
#1015 report a similar problem but the result did not helped me fixing my issue
See what i tried section.
[ ] Regression
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Current behavior
I have an application that expose a public HTTP api.
The "gateway" communicate with microservices through GRPC.
@Injectable()
export class AuthService {
constructor(private readonly commandBus: CommandBus, private readonly queryBus: QueryBus) {}
// ...
async assertEmailDoesNotExist(email: string) {
const emailAlreadyExist = await this.queryBus.execute(new DoesEmailExistQuery(email));
if (emailAlreadyExist) {
// >>>> Here <<<<
// I would like to display an "ALREADY_EXIST"
// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
const exception = new RpcException({ message: 'Email already exist', status: 6 });
throw exception;
}
}
}but I get
{
"level":50,
/// ...
"context":"ExceptionsHandler",
"msg":"2 UNKNOWN: Email already exist",
"v":1
}in my log (custom pino logger).
Expected behavior
{
"level":50,
/// ...
"context":"ExceptionsHandler",
"msg":"6 ALREADY_EXISTS: Email already exist",
"v":1
}What i tried
- setting the code of the exception (like
ex.code = xxx) - passing an object
RpcException({ message: 'Email already exist', status: 6 }) - doing a rpc filter (as suggested in issue)
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, RpcExceptionFilter } from '@nestjs/common';
import { RpcException, BaseRpcExceptionFilter } from '@nestjs/microservices';
import { Observable, throwError } from 'rxjs';
export class HttpExceptionFilter extends BaseRpcExceptionFilter implements RpcExceptionFilter {
catch(exception: RpcException, host: ArgumentsHost): Observable<unknown> {
if (exception instanceof RpcException) {
return throwError({status: 6})
}
return super.catch(exception, host);
}
}Ultimatly, without doc, I lack knowledge how to solve my problem. I did try but I guess not in the right direction
Minimal reproduction of the problem with instructions
Not really minimal (but close two, one api gateway, two microservices) but you can found the codebase here: https://github.com/tychota/shitake
To run it:
yarn- create a db "events" and a db "accounts" in postgres with user "shitake"/"password"
- (in one terminal)
yarn webpack -f webpack.config.js - (in an other)
node dist/server.js - go to swagger: http://localhost:3001/api/#/auth/post_auth_register
- register twice with same email
What is the motivation / use case for changing the behavior?
In http, it is super nice, you can just throw a ConflictException and boom, you have a 429.
In GRPC world it is not as nice :/
You have to play with message string (hardcoded stuff) and ultimatly not every status code are equal (https://github.com/grpc/grpc/blob/master/doc/statuscodes.md) (like a 401 in HTTp may be expected but a 500 isn't). Here you have just the equivalence of 500, with all what is implied (logging of a 500).
Environment
Nest version:
"@nestjs/common": "^6.0.5",
"@nestjs/cqrs": "^6.0.0",
For Tooling issues:
- Node version: v8.12.0
- Platform: Linux, Gentoo
Closing
Let me know if it is clear enough.