Dokumentasi gRPC error code dapat dilihat di https://grpc.io/docs/guides/error/, namun dokumentasi tersebut agak kurang lengkap.
Anda dapat lihat dokumentasi implementasi yg lebih lengkap di https://avi.im/grpc-errors/
Pada modul ini kami coba jelaskan implementasi error handling untuk unary grpc.
Buka file protos/greet.proto, tambahkan rpc dan message baru
syntax = "proto3"; package greet; message Greeting { string first_name = 1; string last_name = 2; } message GreetRequest{ Greeting greeting = 1; } message GreetResponse{ string result = 1; } //streaming request message GreetManyRequest{ Greeting greeting = 1; } //streaming response message GreetManyResponse{ string result = 1; } //client streaming msg request message LongGreetRequest { Greeting greet = 1; } message LongGreetResponse { string result = 1; } //bi directional streaming message GreetEveryoneRequest { Greeting greet = 1; } message GreetEveryoneResponse { string result = 1; } service GreetService { //unary rpc Greet (GreetRequest) returns (GreetResponse){}; //server streaming rpc GreetManyTimes (GreetManyRequest) returns (stream GreetManyResponse){}; //client streaming rpc LongGreet (stream LongGreetRequest) returns (LongGreetResponse){}; //bidi streaming rpc GreetEveryone (stream GreetEveryoneRequest) returns (stream GreetEveryoneResponse){}; //contoh implementasi error handling unary rpc SquareRoot (SquareRootRequest) returns (SquareRootResponse); } //message untuk contoh implementasi handling erro unary message SquareRootRequest { int32 number = 1; } //message untuk contoh implementasi handling erro unary message SquareRootResponse { double number_root = 1; }
Kemudian kita compile, buka command prompt dan jalankan perintah berikut:
protoc-gen-grpc --proto_path=protos --js_out=import_style=commonjs,binary:server --grpc_out=server protos/greet.proto
File greet_pb.js dan greet_grpc_pb.js akan diupdate.
Kemudian kita buka file server/index.js, kita tambahkan implementasi error handling untuk service squareRoot
var grpc = require('grpc'); var greets = require('./greet_pb'); var service = require('./greet_grpc_pb'); function greet (call, callback){ var greeting = new greets.GreetResponse(); greeting.setResult( "Hello, " + call.request.getGreeting().getFirstName() + " " + call.request.getGreeting().getLastName() ); callback(null, greeting); } //implementasi streaming API function greetManyTimes (call, callback){ var firstName = call.request.getGreeting().getFirstName(); //kita simulasikan streaming. let count = 0, intervalID = setInterval(function(){ var greetManyResponse = new greets.GreetManyResponse(); greetManyResponse.setResult(firstName); //streaming goes here call.write(greetManyResponse); if(++count > 9){ clearInterval(intervalID); call.end() //server selesai mengirim message. } }, 1000); } //client streaming function longGreet (call, callback){ call.on('data', request=>{ var fullname = request.getGreet().getFirstName() + ' ' + request.getGreet().getLastName(); console.log('hello, ' + fullname); }); call.on('error', (error)=>{ console.error(error); }); call.on('end', ()=>{ var response = new greets.LongGreetResponse(); response.setResult('Long greet client streaming..'); callback(null, response); }); } //bidi streaming async function sleep(interval){ return new Promise((resolve)=>{ setTimeout(()=> resolve(), interval) }); } async function greetEveryone(call, callback){ call.on('data', request =>{ var fullname = request.getGreet().getFirstName() + " " + request.getGreet().getLastName(); console.log('Data from: ' + fullname); }); call.on('error', error =>{ log.error(error); }); call.on('end', ()=>{ console.log('End bidi streaming...'); }); //simulasi streaming menggunakan for loop for(var i=0; i<10; i++){ var response = new greets.GreetEveryoneResponse(); response.setResult('Data ke: ' + i); call.write(response); await sleep(1000); } call.end(); } //contoh implementasi error unary function squareRoot(call, callback){ var number = call.request.getNumber(); if (number >=0){ var numberRoot = Math.sqrt(number); var response = new greets.SquareRootResponse(); response.setNumberRoot(numberRoot); callback(null, response); }else{ //error handling return callback({ code: grpc.status.INVALID_ARGUMENT, message: 'Number is negatif : ' + number, }); } } function main(){ var Server = new grpc.Server(); Server.addService(service.GreetServiceService, { greet: greet, greetManyTimes: greetManyTimes, longGreet:longGreet, greetEveryone:greetEveryone, squareRoot: squareRoot, //implementasi error handling }); Server.bindAsync("127.0.0.1:50051", grpc.ServerCredentials.createInsecure(), ()=>{ Server.start(); }); console.log("Server running.."); } main()
Buka file client, tambahkan code untuk melakukan error call dengan passing data negatif.
var grpc = require('grpc'); var greets = require('../server/greet_pb'); var service = require('../server/greet_grpc_pb'); // function unary(){ // var client = new service.GreetServiceClient('localhost:50051', grpc.credentials.createInsecure()); // var request = new greets.GreetRequest(); // var greeting = new greets.Greeting(); // greeting.setFirstName("Test1"); // greeting.setLastName("Test2"); // request.setGreeting(greeting); // client.greet(request, (error, response)=>{ // if (!error){ // console.log("Response: ", response.getResult()); // }else{ // console.error(error); // } // }); // } // function callGreetMany(){ // var client = new service.GreetServiceClient( // 'localhost:50051', grpc.credentials.createInsecure() // ); // var request = new greets.GreetManyRequest(); // var greeting = new greets.Greeting(); // greeting.setFirstName("Streaming"); // greeting.setLastName("API"); // request.setGreeting(greeting); // var call = client.greetManyTimes(request, ()=>{}); // call.on("data", (response)=>{ // console.log('Client streaming response: ', response.getResult()); // }); // call.on("status", (status)=>{ // console.log(status.details); // }); // call.on("error", (error)=>{ // console.error(error.details); // }); // call.on("end", ()=>{ // console.log("streaming end.."); // }); // } // function callLongGreeting(){ // var client = new service.GreetServiceClient( // 'localhost:50051', grpc.credentials.createInsecure() // ); // var request = new greets.LongGreetRequest(); // var call = client.longGreet(request, (error, response)=>{ // if(!error){ // console.log('server response: ', response.getResult()); // }else{ // console.error(error); // } // }); // let count = 0, intervalID = setInterval(function(){ // console.log('Sending message ' + count); // //request 1 // var request = new greets.LongGreetRequest(); // var greeting = new greets.Greeting(); // greeting.setFirstName('Client'); // greeting.setLastName('Streaming'); // request.setGreet(greeting); // //request 2 // var request2 = new greets.LongGreetRequest(); // var greeting2 = new greets.Greeting(); // greeting2.setFirstName('Client2'); // greeting2.setLastName('Streaming2'); // request2.setGreet(greeting2); // call.write(request); // call.write(request2); // if(++count > 3){ // clearInterval(intervalID); // call.end(); // } // }, 1000); // } // //bidi streaming // async function sleep(interval){ // return new Promise((resolve)=>{ // setTimeout(()=> resolve(), interval) // }); // } // async function callBiDirect(){ // var client = new service.GreetServiceClient( // 'localhost:50051', grpc.credentials.createInsecure() // ); // var call = client.greetEveryone(request, (error, response)=>{ // console.log('Server response: ' + response); // }); // call.on('data', response=>{ // console.log('Response from server: ' + response.getResult()); // }); // call.on('error', error =>{ // console.error(error); // }); // call.on('end', ()=>{ // console.log('End bidi...'); // }); // //simulasi streaming data menggunakan for loop // for(var i=0; i<10; i++){ // var greeting = new greets.Greeting(); // greeting.setFirstName('Bidi'); // greeting.setLastName('Streaming'); // var request = new greets.GreetEveryoneRequest(); // request.setGreet(greeting); // call.write(request); // await sleep(1500); // } // call.end(); // } function doErrorCall(){ console.log("Implementasi RPC error handling"); var client = new service.GreetServiceClient( 'localhost:50051', grpc.credentials.createInsecure() ); var number = -4; var squareRootRequest = new greets.SquareRootRequest(); squareRootRequest.setNumber(number); client.squareRoot(squareRootRequest, (error, response)=>{ if(!error) { console.log("Square root : " + response.getNumberRoot()); }else{ console.error(error.message); } }); } doErrorCall(); //callBiDirect(); // callLongGreeting(); //callGreetMany(); //unary()
Buka command prompt, masuk ke direktori sever, kemudian jalankan service
$ node index.js
Buka command prompt kedua, masuk ke direktori client, kemudian jalankan code client.
$ node client.js
Implementasi RPC error handling
3 INVALID_ARGUMENT: Number is negatif : -4
Sesuai ekspektasi, server akan mengembalikan error code dan details.
Dapat diambil kesimpulan, cara error handling, sama dengan kita membuat program pada umumnya. Hanya yang perlu kita ikuti adalah aturan error code, yang dapat diakses melalui object grpc.status