Skip to content

Commit a8416b5

Browse files
Refactor error handling in grpcwebclientbase
1 parent daf7cc8 commit a8416b5

File tree

7 files changed

+248
-80
lines changed

7 files changed

+248
-80
lines changed

javascript/net/grpc/web/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ closure_js_library(
121121
visibility = ["//visibility:public"],
122122
deps = [
123123
":clientreadablestream",
124+
":error",
124125
":generictransportinterface",
125126
":grpcwebstreamparser",
126127
":status",

javascript/net/grpc/web/grpcwebclientbase.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,45 @@ class GrpcWebClientBase {
9696
* @export
9797
*/
9898
rpcCall(method, requestMessage, metadata, methodDescriptor, callback) {
99+
/**
100+
* @implements {ClientReadableStream}
101+
*/
102+
class ClientUnaryCallImpl {
103+
/**
104+
* @param {!ClientReadableStream<RESPONSE>} stream
105+
* @template RESPONSE
106+
*/
107+
constructor(stream) {
108+
this.stream = stream;
109+
}
110+
111+
/**
112+
* @override
113+
*/
114+
on(eventType, callback) {
115+
if (eventType == 'data' || eventType == 'error') {
116+
// unary call responses and errors should be handled by the main
117+
// (err, resp) => ... callback
118+
return this;
119+
}
120+
return this.stream.on(eventType, callback);
121+
}
122+
123+
/**
124+
* @override
125+
*/
126+
removeListener(eventType, callback) {
127+
return this.stream.removeListener(eventType, callback);
128+
}
129+
130+
/**
131+
* @override
132+
*/
133+
cancel() {
134+
this.stream.cancel();
135+
}
136+
}
137+
99138
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
100139
method, requestMessage, MethodType.UNARY, methodDescriptor);
101140
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
@@ -105,7 +144,7 @@ class GrpcWebClientBase {
105144
var stream = /** @type {!ClientReadableStream<?>} */ (invoker.call(
106145
this, methodDescriptor.createRequest(requestMessage, metadata)));
107146
GrpcWebClientBase.setCallback_(stream, callback, false);
108-
return stream;
147+
return new ClientUnaryCallImpl(stream);
109148
}
110149

111150
/**

javascript/net/grpc/web/grpcwebclientreadablestream.js

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ goog.module.declareLegacyNamespace();
3434
const ClientReadableStream = goog.require('grpc.web.ClientReadableStream');
3535
const ErrorCode = goog.require('goog.net.ErrorCode');
3636
const EventType = goog.require('goog.net.EventType');
37+
const GrpcWebError = goog.require('grpc.web.Error');
3738
const GrpcWebStreamParser = goog.require('grpc.web.GrpcWebStreamParser');
3839
const StatusCode = goog.require('grpc.web.StatusCode');
3940
const XhrIo = goog.require('goog.net.XhrIo');
@@ -103,7 +104,7 @@ class GrpcWebClientReadableStream {
103104
/**
104105
* @const
105106
* @private
106-
* @type {!Array<function(...):?>} The list of error callbacks
107+
* @type {!Array<function(!GrpcWebError)>} The list of error callbacks
107108
*/
108109
this.onErrorCallbacks_ = [];
109110

@@ -150,6 +151,11 @@ class GrpcWebClientReadableStream {
150151
var byteSource = new Uint8Array(
151152
/** @type {!ArrayBuffer} */ (self.xhr_.getResponse()));
152153
} else {
154+
self.handleError_({
155+
code: StatusCode.UNKNOWN,
156+
message: 'Unknown Content-type received.',
157+
metadata: {},
158+
});
153159
return;
154160
}
155161
var messages = self.parser_.parse(byteSource);
@@ -184,11 +190,11 @@ class GrpcWebClientReadableStream {
184190
grpcStatusMessage = trailers[GRPC_STATUS_MESSAGE];
185191
delete trailers[GRPC_STATUS_MESSAGE];
186192
}
187-
self.sendStatusCallbacks_(/** @type {!Status} */ ({
193+
self.handleError_({
188194
code: Number(grpcStatusCode),
189-
details: grpcStatusMessage,
195+
message: decodeURIComponent(grpcStatusMessage),
190196
metadata: trailers,
191-
}));
197+
});
192198
}
193199
}
194200
}
@@ -227,9 +233,10 @@ class GrpcWebClientReadableStream {
227233
if (grpcStatusCode == StatusCode.ABORTED && self.aborted_) {
228234
return;
229235
}
230-
self.sendErrorCallbacks_({
236+
self.handleError_({
231237
code: grpcStatusCode,
232-
message: ErrorCode.getDebugMessage(lastErrorCode)
238+
message: ErrorCode.getDebugMessage(lastErrorCode),
239+
metadata: {},
233240
});
234241
return;
235242
}
@@ -243,20 +250,13 @@ class GrpcWebClientReadableStream {
243250
grpcStatusMessage = self.xhr_.getResponseHeader(GRPC_STATUS_MESSAGE);
244251
}
245252
if (Number(grpcStatusCode) != StatusCode.OK) {
246-
self.sendErrorCallbacks_({
253+
self.handleError_({
247254
code: Number(grpcStatusCode),
248255
message: grpcStatusMessage,
249256
metadata: responseHeaders
250257
});
251258
errorEmitted = true;
252259
}
253-
if (!errorEmitted) {
254-
self.sendStatusCallbacks_(/** @type {!Status} */ ({
255-
code: Number(grpcStatusCode),
256-
details: grpcStatusMessage,
257-
metadata: responseHeaders
258-
}));
259-
}
260260
}
261261

262262
if (!errorEmitted) {
@@ -353,6 +353,23 @@ class GrpcWebClientReadableStream {
353353
return headers;
354354
}
355355

356+
/**
357+
* A central place to handle errors
358+
*
359+
* @private
360+
* @param {!GrpcWebError} error The error object
361+
*/
362+
handleError_(error) {
363+
if (error.code != StatusCode.OK) {
364+
this.sendErrorCallbacks_(error);
365+
}
366+
this.sendStatusCallbacks_(/** @type {!Status} */ ({
367+
code: error.code,
368+
details: decodeURIComponent(error.message || ''),
369+
metadata: error.metadata
370+
}));
371+
}
372+
356373
/**
357374
* @private
358375
* @param {!RESPONSE} data The data to send back
@@ -385,7 +402,7 @@ class GrpcWebClientReadableStream {
385402

386403
/**
387404
* @private
388-
* @param {?} error The error to send back
405+
* @param {!GrpcWebError} error The error to send back
389406
*/
390407
sendErrorCallbacks_(error) {
391408
for (var i = 0; i < this.onErrorCallbacks_.length; i++) {

net/grpc/gateway/examples/echo/commonjs-example/client.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,6 @@ var echoApp = new EchoApp(
6464
{
6565
EchoRequest: EchoRequest,
6666
ServerStreamingEchoRequest: ServerStreamingEchoRequest
67-
},
68-
{
69-
checkGrpcStatusCode: function(status) {
70-
if (status.code != grpc.web.StatusCode.OK) {
71-
EchoApp.addRightMessage('Error code: '+status.code+' "'+
72-
status.details+'"');
73-
}
74-
}
7567
}
7668
);
7769

net/grpc/gateway/examples/echo/echoapp.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ const echoapp = {};
2121
/**
2222
* @param {Object} echoService
2323
* @param {Object} ctors
24-
* @param {Object} handlers
2524
*/
26-
echoapp.EchoApp = function(echoService, ctors, handlers) {
25+
echoapp.EchoApp = function(echoService, ctors) {
2726
this.echoService = echoService;
2827
this.ctors = ctors;
29-
this.handlers = handlers;
3028
};
3129

3230
echoapp.EchoApp.INTERVAL = 500; // ms
@@ -64,7 +62,6 @@ echoapp.EchoApp.prototype.echo = function(msg) {
6462
echoapp.EchoApp.addLeftMessage(msg);
6563
var unaryRequest = new this.ctors.EchoRequest();
6664
unaryRequest.setMessage(msg);
67-
var self = this;
6865
var call = this.echoService.echo(unaryRequest,
6966
{"custom-header-1": "value1"},
7067
function(err, response) {
@@ -78,7 +75,6 @@ echoapp.EchoApp.prototype.echo = function(msg) {
7875
}
7976
});
8077
call.on('status', function(status) {
81-
self.handlers.checkGrpcStatusCode(status);
8278
if (status.metadata) {
8379
console.log("Received metadata");
8480
console.log(status.metadata);
@@ -118,12 +114,10 @@ echoapp.EchoApp.prototype.repeatEcho = function(msg, count) {
118114
var stream = this.echoService.serverStreamingEcho(
119115
streamRequest,
120116
{"custom-header-1": "value1"});
121-
var self = this;
122117
stream.on('data', function(response) {
123118
echoapp.EchoApp.addRightMessage(response.getMessage());
124119
});
125120
stream.on('status', function(status) {
126-
self.handlers.checkGrpcStatusCode(status);
127121
if (status.metadata) {
128122
console.log("Received metadata");
129123
console.log(status.metadata);

net/grpc/gateway/examples/echo/echotest.html

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@
3232
{
3333
EchoRequest: proto.grpc.gateway.testing.EchoRequest,
3434
ServerStreamingEchoRequest: proto.grpc.gateway.testing.ServerStreamingEchoRequest
35-
},
36-
{
37-
checkGrpcStatusCode: function(status) {
38-
if (status.code != grpc.web.StatusCode.OK) {
39-
echoapp.EchoApp.addRightMessage('Error code: '+status.code+' "'+status.details+'"');
40-
}
41-
}
4235
}
4336
);
4437
echoApp.load();

0 commit comments

Comments
 (0)