Skip to content

Commit

Permalink
feat: support google.api.http annotation (#83)
Browse files Browse the repository at this point in the history
* x-goog-request

* add header-params filed in method

* update baseline

* baseline update

* add logic for routing header

* feedback

* params use snake case instead of camel case

* regex match, take 2 element

* lint

* move init request method in test to util as a macro

* feedback
  • Loading branch information
xiaozhenliu-gg5 committed Oct 30, 2019
1 parent 105ecd1 commit 712516f
Show file tree
Hide file tree
Showing 16 changed files with 666 additions and 195 deletions.
11 changes: 11 additions & 0 deletions templates/typescript_gapic/_util.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{%- macro initRequestWithHeaderParam(method) -%}
const request: protosTypes{{ method.inputInterface }} = {};
{%- if method.headerRequestParams.length > 1 %}
{%- set chain = "request" -%}
{%- for field in method.headerRequestParams.slice(0, -1) %}
{{ chain }}.{{ field.toCamelCase() }} = {};
{%- set chain = chain + "." + field.toCamelCase() -%}
{%- endfor %}
{{ chain }}.{{ method.headerRequestParams.slice(-1)[0] }} = '';
{%- endif %}
{%- endmacro -%}
54 changes: 45 additions & 9 deletions templates/typescript_gapic/src/$version/$service_client.ts.njk
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,24 @@ export class {{ service.name }}Client {
protosTypes{{ method.inputInterface }}|undefined, {}|undefined
]>|void {
request = request || {};
let options = optionsOrCallback;
if (typeof options === 'function' && callback === undefined) {
callback = options;
let options: gax.CallOptions;
if (typeof optionsOrCallback === 'function' && callback === undefined) {
callback = optionsOrCallback;
options = {};
}
else {
options = optionsOrCallback as gax.CallOptions;
}
options = options || {};
{%- if method.headerRequestParams.length > 0 %}
options.otherArgs = options.otherArgs || {};
options.otherArgs.headers = options.otherArgs.headers || {};
options.otherArgs.headers[
'x-goog-request-params'
] = gax.routingHeader.fromParams({
'{{ method.headerRequestParams.toString().toSnakeCase() }}': request.{{ method.headerRequestParams.camelCaseBeforeDot("!.") }} || '',
});
{%- endif %}
return this._innerApiCalls.{{ method.name.toCamelCase() }}(request, options, callback);
}
{%- endfor %}
Expand Down Expand Up @@ -442,12 +454,24 @@ export class {{ service.name }}Client {
protosTypes{{ method.outputInterface }}|undefined, {}|undefined
]>|void {
request = request || {};
let options = optionsOrCallback;
if (typeof options === 'function' && callback === undefined) {
callback = options;
let options: gax.CallOptions;
if (typeof optionsOrCallback === 'function' && callback === undefined) {
callback = optionsOrCallback;
options = {};
}
else {
options = optionsOrCallback as gax.CallOptions;
}
options = options || {};
{%- if method.headerRequestParams.length > 0 %}
options.otherArgs = options.otherArgs || {};
options.otherArgs.headers = options.otherArgs.headers || {};
options.otherArgs.headers[
'x-goog-request-params'
] = gax.routingHeader.fromParams({
'{{ method.headerRequestParams.toString().toSnakeCase() }}': request.{{ method.headerRequestParams.camelCaseBeforeDot("!.") }} || '',
});
{%- endif %}
return this._innerApiCalls.{{ method.name.toCamelCase() }}(request, options, callback);
}
{%- endfor %}
Expand Down Expand Up @@ -486,12 +510,24 @@ export class {{ service.name }}Client {
protosTypes{{ method.outputInterface }}
]>|void {
request = request || {};
let options = optionsOrCallback;
if (typeof options === 'function' && callback === undefined) {
callback = options;
let options: gax.CallOptions;
if (typeof optionsOrCallback === 'function' && callback === undefined) {
callback = optionsOrCallback;
options = {};
}
else {
options = optionsOrCallback as gax.CallOptions;
}
options = options || {};
{%- if method.headerRequestParams.length > 0 %}
options.otherArgs = options.otherArgs || {};
options.otherArgs.headers = options.otherArgs.headers || {};
options.otherArgs.headers[
'x-goog-request-params'
] = gax.routingHeader.fromParams({
'{{ method.headerRequestParams.toString().toSnakeCase() }}': request.{{ method.headerRequestParams.camelCaseBeforeDot("!.") }} || '',
});
{%- endif %}
return this._innerApiCalls.{{ method.name.toCamelCase() }}(request, options, callback);
}
{%- endfor %}
Expand Down
13 changes: 7 additions & 6 deletions templates/typescript_gapic/test/gapic-$service-$version.ts.njk
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{% import "../_license.njk" as license -%}
{% import "../_util.njk" as util -%}
{{license.license()}}
'use strict';

import * as protosTypes from '../protos/protos';
const assert = require('assert');
const {{ service.name.toLowerCase() }}Module = require('../src');
{% if (service.streaming.length > 0) %}
Expand Down Expand Up @@ -127,7 +128,7 @@ describe('{{ service.name }}Client', () => {
projectId: 'bogus',
});
// Mock request
const request = {};
{{ util.initRequestWithHeaderParam(method) }}
// Mock response
const expectedResponse = {};
// Mock gRPC layer
Expand All @@ -149,7 +150,7 @@ describe('{{ service.name }}Client', () => {
projectId: 'bogus',
});
// Mock request
const request = {};
{{ util.initRequestWithHeaderParam(method) }}
// Mock response
const expectedResponse = {};
// Mock gRPC layer
Expand All @@ -175,7 +176,7 @@ describe('{{ service.name }}Client', () => {
projectId: 'bogus',
});
// Mock request
const request = {};
{{ util.initRequestWithHeaderParam(method) }}
// Mock response
const expectedResponse = {};
// Mock gRPC layer
Expand All @@ -200,7 +201,7 @@ describe('{{ service.name }}Client', () => {
projectId: 'bogus',
});
// Mock request
const request = {};
{{ util.initRequestWithHeaderParam(method) }}
// Mock response
const expectedResponse = {};
// Mock gRPC layer
Expand Down Expand Up @@ -320,7 +321,7 @@ describe('{{ service.name }}Client', () => {
projectId: 'bogus',
});
// Mock request
const request = {};
{{ util.initRequestWithHeaderParam(method) }}
// Mock response
const expectedResponse = {};
// Mock Grpc layer
Expand Down
4 changes: 4 additions & 0 deletions typescript/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ interface String {
toKebabCase(): string;
toSnakeCase(): string;
}

interface Array<T> {
camelCaseBeforeDot(this: string[], joiner: string): string;
}
15 changes: 15 additions & 0 deletions typescript/src/schema/proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface MethodDescriptorProto
retryableCodesName: string;
retryParamsName: string;
timeoutMillis?: number;
headerRequestParams: string[];
}

export class RetryableCodeMap {
Expand Down Expand Up @@ -288,6 +289,16 @@ function toLRInterface(type: string, inputType: string) {
return inputType.replace(/\.([^.]+)$/, '.I' + type);
}

export function getHeaderParams(rule: plugin.google.api.IHttpRule): string[] {
const message =
rule.post || rule.delete || rule.get || rule.put || rule.patch;
if (message) {
const res = message.match(/{(.*?)=/);
return res && res[1] ? res[1].split('.') : [];
}
return [];
}

function getMethodConfig(
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig,
serviceName: string,
Expand Down Expand Up @@ -382,6 +393,10 @@ function augmentMethod(
if (method.methodConfig.timeout) {
method.timeoutMillis = milliseconds(method.methodConfig.timeout);
}
if (method.options && method.options['.google.api.http']) {
const httpRule = method.options['.google.api.http'];
method.headerRequestParams = getHeaderParams(httpRule);
} else method.headerRequestParams = [];
return method;
}

Expand Down
11 changes: 11 additions & 0 deletions typescript/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,14 @@ String.prototype.toSnakeCase = function(this: string): string {
}
return words.join('_');
};

Array.prototype.camelCaseBeforeDot = function(
this: string[],
joiner: string
): string {
if (this.length <= 1) {
return this.toString().toCamelCase();
}
const res = this.slice(0, -1).map(w => w.toCamelCase());
return res.join(joiner) + joiner + this[this.length - 1];
};

0 comments on commit 712516f

Please sign in to comment.