Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support google.api.http annotation #83

Merged
merged 11 commits into from
Oct 30, 2019
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];
};
Loading