Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I send a custom Error message from server to client GRPC?

Tags:

I have created a simple GRPC server and client .

What i want to do is to create a custom error in the server and pass it to the client. My code looks as follows:

Server.js

var error = require('error');

var PROTO_PATH = grpc.load(__dirname + '/proto/hello.proto');
var hello_proto = PROTO_PATH.hello;

function sayHello(call, callback) {

    try {
        var jsErr = new Error('MY_ERROR');
        jsErr.newStatus = 401;
        jsErr.newMessage = 'custom unAuthorized error';
        console.log(Object.getOwnPropertyNames(jsErr));
        console.log(jsErr);
        callback(jsErr);

    } catch(e) {
        callback(e);
    }
}

function sayHelloAgain(call, callback) {
    callback(null, {message: 'Hello Again ' + call.request.name});
}

function main() {

    var server = new grpc.Server();
    server.addProtoService(hello_proto.Hello.service, {sayHello: sayHello,sayHelloAgain: sayHelloAgain });
    server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
    server.start();
}

main();

Client.js

var grpc = require('grpc');

var PROTO_PATH = grpc.load(__dirname + '/proto/hello.proto');
var hello_proto = PROTO_PATH.hello;

function main() {
    var client = new hello_proto.Hello('localhost:50051',grpc.credentials.createInsecure());
    var user;
    if (process.argv.length >= 3) {
        user = process.argv[2];
    } else {
        user = 'world';
    }

    client.sayHello({name: user}, function(err, response) {

        console.log(Object.getOwnPropertyNames(err));
        console.log(err);
    });
}

main();

and my proto file

syntax = "proto3";

package hello;

service Hello {
    rpc sayHello(sayHelloRequest) returns (sayHelloResponse) {}
    rpc sayHelloAgain(sayHelloRequest) returns (sayHelloResponse) {}
}


message sayHelloRequest {
    string name = 1;
}

message sayHelloResponse {
    string message = 1;
}

when i run the cient the result from each looks like this

Server .

[ 'stack', 'message', 'newStatus', 'newMessage' ]
{ [Error: MY_ERROR] newStatus: 401, newMessage: 'custom unAutorized error' }

Client .

[ 'stack', 'message', 'code', 'metadata' ]
{ [Error: MY_ERROR] code: 2, metadata: Metadata { _internal_repr: {} } }

So my created custom javascript error's newStatus, newMessage properties have removed and it has converted to GRPC standard error message .

My Questions are

  1. Is it possible to send a custom message to client ?
  2. Can i create a GRPC error , not a javascript error ?
  3. one way to send custom attributes to client is i think is add the custom data to Metadata . but i am also not sure how to do it .
like image 625
Kanishka Panamaldeniya Avatar asked Nov 24 '16 02:11

Kanishka Panamaldeniya


People also ask

Can gRPC server call client?

gRPC users typically call these APIs on the client side and implement the corresponding API on the server side. On the server side, the server implements the methods declared by the service and runs a gRPC server to handle client calls.

What is client stub in gRPC?

A client contains a gRPC stub that mirrors the methods available on the server. The client makes RPC calls using the generated gRPC stubs, which sends the request to and receives the response from the gRPC server, serializing and deserializing the request and response messages.

How does gRPC communicate?

Rather than using a textual format such as JSON or XML, gRPC uses a protocol buffer–based binary protocol to communicate with gRPC services and clients. Also, gRPC implements protocol buffers on top of HTTP/2, which makes it even faster for inter-process communication.


2 Answers

There is a helpful reply to this same question on the gRPC Google Group: https://groups.google.com/d/msg/grpc-io/X_bUx3T8S7s/x38FU429CgAJ

You can send a custom status message to the client using the Error object's message property. In your example, that is "MY_ERROR". The status code should be in the "code" property, just like how you see it on the client side.

If you want to use the gRPC status structure instead of a JavaScript error, you can do so by populating the "code" property and the "message" or "details" property of the object.

If you want to send metadata, you should construct an instance of the grpc.Metadata class, then add key/value pairs to the resulting object. Then you can pass it as the third argument of the callback or set the error's "metadata" property to send it to the client with the error.

Please note that the status codes that gRPC uses are not HTTP status codes, but gRPC specific codes that are defined in grpc.status. You should only set the error's code property using those codes. If you want to send your own codes, use metadata instead.

I'll illustrate what's written above with some examples.

To send a custom message with the error, construct an Error with the message. This sets the message property:

var jsErr = new Error('Unauthorized');

As mentioned above, it's probably not useful to directly set gRPC status codes in your case. But, for reference, the gRPC status code can be set through the error's code property:

jsErr.code = grpc.status.PERMISSION_DENIED;

To send your own error codes, or other information, use metadata:

var metadata = new grpc.Metadata();
metadata.set('key1', 'value2');
metadata.set('key2', 'value2');

jsErr.metadata = metadata;

Now, if the server constructs the error as above and the client outputs the returned error with:

console.log(Object.getOwnPropertyNames(err));
console.log(err);
console.log(err.metadata);

then the client output is:

[ 'stack', 'message', 'code', 'metadata' ]
{ [Error: Unauthorized]
  code: 7,
  metadata: Metadata { _internal_repr: { key1: [Object], key2: [Object] } } }
Metadata { _internal_repr: { key1: [ 'value2' ], key2: [ 'value2' ] } }
like image 189
Max Smolens Avatar answered Sep 22 '22 07:09

Max Smolens


1.Yes 2.Maybe

Avoid sending special objects (like new Error) over the wire. Send simple object with an error property and look for its value on the other end. See http://json.org/ to have an overview of easy transferable data.

inside Server.js try

function sayHello(call, callback) {

    try {
        var myCustomError = {};
        myCustomError.newStatus = 401;
        myCustomError.newMessage = 'custom unAuthorized error';
        console.log(Object.getOwnPropertyNames(myCustomError ));
        console.log(myCustomError);
        callback(null, {error: myCustomError, message: ""});

    } catch(e) {
        callback(e);
    }
}

inside the Client.js

client.sayHello({name: user}, function(err, response) {
    var myCustomError= response.error;
    if (myCustomError) {
        console.log(Object.getOwnPropertyNames(myCustomError));
        console.log(myCustomError);
    }
});
like image 29
Walle Cyril Avatar answered Sep 20 '22 07:09

Walle Cyril