Skip to content

Commit 5674498

Browse files
authored
Merge pull request #2711 from n0v1/feat/method-options
grpc-loader: Expose method options
2 parents b2e9d04 + 6c7225f commit 5674498

File tree

4 files changed

+150
-0
lines changed

4 files changed

+150
-0
lines changed

packages/proto-loader/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@types/node": "^10.17.26",
5858
"@types/yargs": "^17.0.24",
5959
"clang-format": "^1.2.2",
60+
"google-proto-files": "^3.0.2",
6061
"gts": "^3.1.0",
6162
"rimraf": "^3.0.2",
6263
"ts-node": "^10.9.2",

packages/proto-loader/src/index.ts

+51
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,34 @@ export interface EnumTypeDefinition extends ProtobufTypeDefinition {
115115
format: 'Protocol Buffer 3 EnumDescriptorProto';
116116
}
117117

118+
export enum IdempotencyLevel {
119+
IDEMPOTENCY_UNKNOWN = 'IDEMPOTENCY_UNKNOWN',
120+
NO_SIDE_EFFECTS = 'NO_SIDE_EFFECTS',
121+
IDEMPOTENT = 'IDEMPOTENT'
122+
}
123+
124+
export interface NamePart {
125+
name_part: string;
126+
is_extension: boolean;
127+
}
128+
129+
export interface UninterpretedOption {
130+
name?: NamePart[];
131+
identifier_value?: string;
132+
positive_int_value?: number;
133+
negative_int_value?: number;
134+
double_value?: number;
135+
string_value?: string;
136+
aggregate_value?: string;
137+
}
138+
139+
export interface MethodOptions {
140+
deprecated: boolean;
141+
idempotency_level: IdempotencyLevel;
142+
uninterpreted_option: UninterpretedOption[];
143+
[k: string]: unknown;
144+
}
145+
118146
export interface MethodDefinition<RequestType, ResponseType, OutputRequestType=RequestType, OutputResponseType=ResponseType> {
119147
path: string;
120148
requestStream: boolean;
@@ -126,6 +154,7 @@ export interface MethodDefinition<RequestType, ResponseType, OutputRequestType=R
126154
originalName?: string;
127155
requestType: MessageTypeDefinition;
128156
responseType: MessageTypeDefinition;
157+
options: MethodOptions;
129158
}
130159

131160
export interface ServiceDefinition {
@@ -220,6 +249,27 @@ function createSerializer(cls: Protobuf.Type): Serialize<object> {
220249
};
221250
}
222251

252+
function mapMethodOptions(options: Partial<MethodOptions>[] | undefined): MethodOptions {
253+
return (options || []).reduce((obj: MethodOptions, item: Partial<MethodOptions>) => {
254+
for (const [key, value] of Object.entries(item)) {
255+
switch (key) {
256+
case 'uninterpreted_option' :
257+
obj.uninterpreted_option.push(item.uninterpreted_option as UninterpretedOption);
258+
break;
259+
default:
260+
obj[key] = value
261+
}
262+
}
263+
return obj
264+
},
265+
{
266+
deprecated: false,
267+
idempotency_level: IdempotencyLevel.IDEMPOTENCY_UNKNOWN,
268+
uninterpreted_option: [],
269+
}
270+
) as MethodOptions;
271+
}
272+
223273
function createMethodDefinition(
224274
method: Protobuf.Method,
225275
serviceName: string,
@@ -242,6 +292,7 @@ function createMethodDefinition(
242292
originalName: camelCase(method.name),
243293
requestType: createMessageDefinition(requestType, fileDescriptors),
244294
responseType: createMessageDefinition(responseType, fileDescriptors),
295+
options: mapMethodOptions(method.parsedOptions),
245296
};
246297
}
247298

packages/proto-loader/test/descriptor_type_test.ts

+50
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { rpcFileDescriptorSet } from '../test_protos/rpc.desc';
2020
import { readFileSync } from 'fs';
2121

2222
import * as proto_loader from '../src/index';
23+
import { dirname } from 'path';
2324

2425
// Relative path from build output directory to test_protos directory
2526
const TEST_PROTO_DIR = `${__dirname}/../../test_protos/`;
@@ -128,4 +129,53 @@ describe('Descriptor types', () => {
128129
// This will throw if the file descriptor object cannot be parsed
129130
proto_loader.loadFileDescriptorSetFromObject(rpcFileDescriptorSet);
130131
});
132+
133+
it('Can parse method options into object correctly', () => {
134+
const includeDirs = [
135+
dirname(require.resolve('google-proto-files/package.json'))
136+
];
137+
const packageDefinition = proto_loader.loadSync(`${TEST_PROTO_DIR}/method_options.proto`, { includeDirs });
138+
assert('Hello' in packageDefinition);
139+
const service = packageDefinition.Hello as proto_loader.ServiceDefinition
140+
assert.deepStrictEqual(service.Hello.options, {
141+
deprecated: true,
142+
idempotency_level: 'NO_SIDE_EFFECTS',
143+
uninterpreted_option: [{
144+
name: {
145+
name_part: 'foo',
146+
is_extension: false,
147+
},
148+
identifier_value: 'bar',
149+
positive_int_value: 9007199254740991,
150+
negative_int_value: -9007199254740991,
151+
double_value: 1.2345,
152+
string_value: 'foobar',
153+
aggregate_value: 'foobar'
154+
}],
155+
'(google.api.http)': {
156+
post: '/hello',
157+
body: '*',
158+
response_body: '*',
159+
additional_bindings: {}
160+
},
161+
'(google.api.method_signature)': 'bar'
162+
})
163+
assert.deepStrictEqual(service.HelloWithoutOptions.options, {
164+
deprecated: false,
165+
idempotency_level: 'IDEMPOTENCY_UNKNOWN',
166+
uninterpreted_option: []
167+
})
168+
assert.deepStrictEqual(service.HelloWithSomeOptions.options, {
169+
deprecated: true,
170+
idempotency_level: 'IDEMPOTENCY_UNKNOWN',
171+
uninterpreted_option: [],
172+
'(google.api.http)': {
173+
get: '/hello',
174+
additional_bindings: {
175+
body: '*',
176+
get: '/hello-world'
177+
}
178+
},
179+
})
180+
})
131181
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
syntax = "proto3";
2+
3+
import "google/api/annotations.proto";
4+
import "google/api/client.proto";
5+
import "google/api/httpbody.proto";
6+
7+
message Empty {}
8+
9+
message MethodSignature {
10+
repeated string method_signature = 1;
11+
}
12+
13+
service Hello {
14+
rpc Hello (Empty) returns (Empty) {
15+
option deprecated = true;
16+
option idempotency_level = NO_SIDE_EFFECTS;
17+
option uninterpreted_option = {
18+
name: {
19+
name_part: 'foo'
20+
is_extension: false
21+
}
22+
identifier_value: 'bar'
23+
positive_int_value: 9007199254740991
24+
negative_int_value: -9007199254740991
25+
double_value: 1.2345
26+
string_value: 'foobar'
27+
aggregate_value: 'foobar'
28+
};
29+
option (google.api.http) = {
30+
post: "/hello"
31+
body: "*"
32+
response_body: "*"
33+
additional_bindings: {}
34+
};
35+
option (google.api.method_signature) = 'bar';
36+
}
37+
rpc HelloWithoutOptions (Empty) returns (Empty) {}
38+
rpc HelloWithSomeOptions (Empty) returns (Empty) {
39+
option deprecated = true;
40+
option (google.api.http) = {
41+
get: "/hello"
42+
additional_bindings: {
43+
get: "/hello-world"
44+
body: "*"
45+
}
46+
};
47+
}
48+
}

0 commit comments

Comments
 (0)