Error handling & limitations
Mapping exceptions to gRPC statuses
When a controller method (or a guard) throws, @danet/grpc converts the error into a gRPC status code returned to the client.
Danet's built-in HTTP exceptions are mapped to the closest gRPC status:
| Danet exception | HTTP | gRPC status |
|---|---|---|
BadRequestException | 400 | INVALID_ARGUMENT |
UnauthorizedException | 401 | UNAUTHENTICATED |
ForbiddenException | 403 | PERMISSION_DENIED |
NotFoundException | 404 | NOT_FOUND |
ConflictException | 409 | ALREADY_EXISTS |
PreconditionFailedException | 412 | FAILED_PRECONDITION |
TooManyRequestsException | 429 | RESOURCE_EXHAUSTED |
InternalServerErrorException | 500 | INTERNAL |
NotImplementedException | 501 | UNIMPLEMENTED |
ServiceUnavailableException | 503 | UNAVAILABLE |
GatewayTimeoutException | 504 | DEADLINE_EXCEEDED |
Any other error maps to UNKNOWN.
ts
@GrpcMethod()
GetUser(@GrpcPayload() request: { id: string }) {
const user = this.users.find(request.id);
if (!user) {
throw new NotFoundException(); // -> NOT_FOUND on the client
}
return user;
}A denied guard throws ForbiddenException, so the client receives PERMISSION_DENIED.
Sending your own message
The built-in exceptions take no constructor argument, so the client only reads the generic description (Not found, Forbidden, ...). Throw an HttpException directly to choose both the status and the text the caller receives:
ts
throw new HttpException(404, `no user with id ${request.id}`);
// -> code NOT_FOUND, details "no user with id 42"Exception filters
Exception filters run for gRPC calls just like for HTTP requests. If a filter returns a value, that value is sent back to the client as the RPC reply instead of an error.
ts
@UseFilter(MyGrpcFilter)
@GrpcController(GreeterService)
export class GreeterController { /* ... */ }Limitations
- Unary RPCs only for now. Streaming RPCs (server-, client- and bidirectional) are skipped — clients calling them receive
UNIMPLEMENTED. Streaming support is planned. - Transport-agnostic middleware only — middleware that depends on HTTP
ctx.req/ctx.reswill not work on gRPC controllers. - No DTO validation on the payload. The Protobuf schema is the contract, so the class-validator based validation used by
@Bodydoes not apply to@GrpcPayload.
Danet