Skip to content

Commit c0880de

Browse files
stephenpluspluscallmehiphop
authored andcommitted
allow setting gRPC metadata (#1546)
* allow setting gRPC metadata * set metadata per call * refactor and test * always default to empty metadata * lint issue * Update grpc-service.js
1 parent 474b242 commit c0880de

2 files changed

Lines changed: 97 additions & 14 deletions

File tree

core/common/src/grpc-service.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ var GRPC_ERROR_CODE_TO_HTTP = {
138138
*
139139
* @param {object} config - Configuration object.
140140
* @param {string} config.baseUrl - The base URL to make API requests to.
141+
* @param {object} config.grpcMetadata - Metadata to send with every request.
141142
* @param {string[]} config.scopes - The scopes required for the request.
142143
* @param {string} config.service - The name of the service.
143144
* @param {object=} config.protoServices - Directly provide the required proto
@@ -158,6 +159,16 @@ function GrpcService(config, options) {
158159
this.grpcCredentials = grpc.credentials.createInsecure();
159160
}
160161

162+
this.grpcMetadata = new grpc.Metadata();
163+
164+
if (config.grpcMetadata) {
165+
for (var prop in config.grpcMetadata) {
166+
if (config.grpcMetadata.hasOwnProperty(prop)) {
167+
this.grpcMetadata.add(prop, config.grpcMetadata[prop]);
168+
}
169+
}
170+
}
171+
161172
this.maxRetries = options.maxRetries;
162173

163174
var apiVersion = config.apiVersion;
@@ -227,8 +238,10 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {
227238
delete reqOpts.autoPaginateVal;
228239

229240
var service = this.getService_(protoOpts);
230-
var grpcOpts = {};
231241

242+
var metadata = this.grpcMetadata;
243+
244+
var grpcOpts = {};
232245
if (is.number(protoOpts.timeout)) {
233246
grpcOpts.deadline = GrpcService.createDeadline_(protoOpts.timeout);
234247
}
@@ -248,16 +261,16 @@ GrpcService.prototype.request = function(protoOpts, reqOpts, callback) {
248261
request: function(_, onResponse) {
249262
respError = null;
250263

251-
service[protoOpts.method](reqOpts, grpcOpts, function(err, resp) {
252-
if (err) {
253-
respError = GrpcService.decorateError_(err);
264+
service[protoOpts.method](reqOpts, metadata, grpcOpts, function(e, resp) {
265+
if (e) {
266+
respError = GrpcService.decorateError_(e);
254267

255268
if (respError) {
256269
onResponse(null, respError);
257270
return;
258271
}
259272

260-
onResponse(err, resp);
273+
onResponse(e, resp);
261274
return;
262275
}
263276

@@ -330,7 +343,7 @@ GrpcService.prototype.requestStream = function(protoOpts, reqOpts) {
330343
shouldRetryFn: GrpcService.shouldRetryRequest_,
331344

332345
request: function() {
333-
return service[protoOpts.method](reqOpts, grpcOpts)
346+
return service[protoOpts.method](reqOpts, self.grpcMetadata, grpcOpts)
334347
.on('metadata', function() {
335348
// retry-request requires a server response before it starts emitting
336349
// data. The closest mechanism grpc provides is a metadata event, but

core/common/test/grpc-service.js

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@ function fakeRetryRequest() {
4343
return (retryRequestOverride || retryRequest).apply(null, arguments);
4444
}
4545

46+
var GrpcMetadataOverride;
4647
var grpcLoadOverride;
4748
var fakeGrpc = {
49+
Metadata: function() {
50+
if (GrpcMetadataOverride) {
51+
return new GrpcMetadataOverride();
52+
}
53+
return new grpc.Metadata();
54+
},
4855
load: function() {
4956
return (grpcLoadOverride || grpc.load).apply(null, arguments);
5057
},
@@ -84,7 +91,10 @@ describe('GrpcService', function() {
8491
var CONFIG = {
8592
proto: {},
8693
service: 'Service',
87-
apiVersion: 'v1'
94+
apiVersion: 'v1',
95+
grpcMetadata: {
96+
property: 'value'
97+
}
8898
};
8999

90100
var OPTIONS = {
@@ -111,6 +121,7 @@ describe('GrpcService', function() {
111121
});
112122

113123
beforeEach(function() {
124+
GrpcMetadataOverride = null;
114125
retryRequestOverride = null;
115126

116127
googleProtoFilesOverride = function() {
@@ -232,6 +243,36 @@ describe('GrpcService', function() {
232243
assert.strictEqual(calledWith[1], OPTIONS);
233244
});
234245

246+
it('should default grpcMetadata to empty metadata', function() {
247+
var fakeGrpcMetadata = {};
248+
249+
GrpcMetadataOverride = function() {
250+
return fakeGrpcMetadata;
251+
};
252+
253+
var config = extend({}, CONFIG);
254+
delete config.grpcMetadata;
255+
256+
var grpcService = new GrpcService(config, OPTIONS);
257+
assert.strictEqual(grpcService.grpcMetadata, fakeGrpcMetadata);
258+
});
259+
260+
it('should create and localize grpcMetadata', function() {
261+
var fakeGrpcMetadata = {
262+
add: function(prop, value) {
263+
assert.strictEqual(prop, Object.keys(CONFIG.grpcMetadata)[0]);
264+
assert.strictEqual(value, CONFIG.grpcMetadata[prop]);
265+
}
266+
};
267+
268+
GrpcMetadataOverride = function() {
269+
return fakeGrpcMetadata;
270+
};
271+
272+
var grpcService = new GrpcService(CONFIG, OPTIONS);
273+
assert.strictEqual(grpcService.grpcMetadata, fakeGrpcMetadata);
274+
});
275+
235276
it('should localize maxRetries', function() {
236277
assert.strictEqual(grpcService.maxRetries, OPTIONS.maxRetries);
237278
});
@@ -738,7 +779,7 @@ describe('GrpcService', function() {
738779
grpcService.protos.Service = {
739780
service: function() {
740781
return {
741-
method: function(reqOpts, grpcOpts, callback) {
782+
method: function(reqOpts, metadata, grpcOpts, callback) {
742783
callback(grpcError500);
743784
}
744785
};
@@ -763,7 +804,7 @@ describe('GrpcService', function() {
763804
grpcService.protos.Service = {
764805
service: function() {
765806
return {
766-
method: function(reqOpts, grpcOpts, callback) {
807+
method: function(reqOpts, metadata, grpcOpts, callback) {
767808
callback(grpcError500);
768809
}
769810
};
@@ -787,7 +828,7 @@ describe('GrpcService', function() {
787828
grpcService.protos.Service = {
788829
service: function() {
789830
return {
790-
method: function(reqOpts, grpcOpts, callback) {
831+
method: function(reqOpts, metadata, grpcOpts, callback) {
791832
callback(unknownError, null);
792833
}
793834
};
@@ -821,6 +862,21 @@ describe('GrpcService', function() {
821862
grpcService.request(PROTO_OPTS, REQ_OPTS, assert.ifError);
822863
});
823864

865+
it('should pass the grpc metadata with the request', function(done) {
866+
grpcService.protos.Service = {
867+
service: function() {
868+
return {
869+
method: function(reqOpts, metadata) {
870+
assert.strictEqual(metadata, grpcService.grpcMetadata);
871+
done();
872+
}
873+
};
874+
}
875+
};
876+
877+
grpcService.request(PROTO_OPTS, REQ_OPTS, assert.ifError);
878+
});
879+
824880
it('should set a deadline if a timeout is provided', function(done) {
825881
var expectedDeadlineRange = [
826882
Date.now() + PROTO_OPTS.timeout - 250,
@@ -830,7 +886,7 @@ describe('GrpcService', function() {
830886
grpcService.protos.Service = {
831887
service: function() {
832888
return {
833-
method: function(reqOpts, grpcOpts) {
889+
method: function(reqOpts, metadata, grpcOpts) {
834890
assert(is.date(grpcOpts.deadline));
835891

836892
assert(grpcOpts.deadline.getTime() > expectedDeadlineRange[0]);
@@ -874,7 +930,7 @@ describe('GrpcService', function() {
874930
grpcService.protos.Service = {
875931
service: function() {
876932
return {
877-
method: function(reqOpts, grpcOpts, callback) {
933+
method: function(reqOpts, metadata, grpcOpts, callback) {
878934
callback(grpcError);
879935
}
880936
};
@@ -896,7 +952,7 @@ describe('GrpcService', function() {
896952
grpcService.protos.Service = {
897953
service: function() {
898954
return {
899-
method: function(reqOpts, grpcOpts, callback) {
955+
method: function(reqOpts, metadata, grpcOpts, callback) {
900956
callback(null, RESPONSE);
901957
}
902958
};
@@ -976,7 +1032,7 @@ describe('GrpcService', function() {
9761032
return fakeDeadline;
9771033
};
9781034

979-
ProtoService.prototype.method = function(reqOpts, grpcOpts) {
1035+
ProtoService.prototype.method = function(reqOpts, metadata, grpcOpts) {
9801036
assert.strictEqual(grpcOpts.deadline, fakeDeadline);
9811037

9821038
GrpcService.createDeadline_ = createDeadline;
@@ -992,6 +1048,20 @@ describe('GrpcService', function() {
9921048
grpcService.requestStream(PROTO_OPTS, REQ_OPTS);
9931049
});
9941050

1051+
it('should pass the grpc metadata with the request', function(done) {
1052+
ProtoService.prototype.method = function(reqOpts, metadata) {
1053+
assert.strictEqual(metadata, grpcService.grpcMetadata);
1054+
setImmediate(done);
1055+
return through.obj();
1056+
};
1057+
1058+
retryRequestOverride = function(_, retryOpts) {
1059+
return retryOpts.request();
1060+
};
1061+
1062+
grpcService.requestStream(PROTO_OPTS, REQ_OPTS);
1063+
});
1064+
9951065
describe('getting gRPC credentials', function() {
9961066
beforeEach(function() {
9971067
delete grpcService.grpcCredentials;

0 commit comments

Comments
 (0)