Skip to content

Commit 333f8ba

Browse files
committed
Apply code review feedback
1 parent 342a0cb commit 333f8ba

File tree

9 files changed

+64
-59
lines changed

9 files changed

+64
-59
lines changed

docs/generated/api.json

+17-17
Original file line numberDiff line numberDiff line change
@@ -851,8 +851,8 @@
851851
},
852852
{
853853
"kind": "Reference",
854-
"text": "TypedHandlerFunction",
855-
"canonicalReference": "@google-cloud/functions-framework!TypedHandlerFunction:interface"
854+
"text": "TypedFunction",
855+
"canonicalReference": "@google-cloud/functions-framework!TypedFunction:interface"
856856
},
857857
{
858858
"kind": "Content",
@@ -1009,7 +1009,7 @@
10091009
{
10101010
"kind": "Interface",
10111011
"canonicalReference": "@google-cloud/functions-framework!InvocationFormat:interface",
1012-
"docComment": "/**\n * The contract for a request deserializer and response serializer.\n */\n",
1012+
"docComment": "/**\n * The contract for a request deserializer and response serializer.\n *\n * @public\n */\n",
10131013
"excerptTokens": [
10141014
{
10151015
"kind": "Content",
@@ -1048,7 +1048,7 @@
10481048
{
10491049
"kind": "MethodSignature",
10501050
"canonicalReference": "@google-cloud/functions-framework!InvocationFormat#deserializeRequest:member(1)",
1051-
"docComment": "/**\n * @param request - the request body as raw bytes\n *\n * @param headers - the headers received on the HTTP request as a map\n */\n",
1051+
"docComment": "/**\n * Creates an instance of the request type from an invocation request.\n *\n * @param request - the request body as raw bytes\n */\n",
10521052
"excerptTokens": [
10531053
{
10541054
"kind": "Content",
@@ -1103,7 +1103,7 @@
11031103
{
11041104
"kind": "MethodSignature",
11051105
"canonicalReference": "@google-cloud/functions-framework!InvocationFormat#serializeResponse:member(1)",
1106-
"docComment": "/**\n * @param response - \n *\n * @param responseHeaders - mutable object providing headers that will be set on the response\n */\n",
1106+
"docComment": "/**\n * Writes the response type to the invocation result.\n *\n * @param responseWriter - interface for writing to the invocation result\n *\n * @param response - the response object\n */\n",
11071107
"excerptTokens": [
11081108
{
11091109
"kind": "Content",
@@ -1177,7 +1177,7 @@
11771177
{
11781178
"kind": "Interface",
11791179
"canonicalReference": "@google-cloud/functions-framework!InvocationRequest:interface",
1180-
"docComment": "/**\n * InvocationRequest represents the properties of an invocation over HTTP.\n */\n",
1180+
"docComment": "/**\n * InvocationRequest represents the properties of an invocation over HTTP.\n *\n * @public\n */\n",
11811181
"excerptTokens": [
11821182
{
11831183
"kind": "Content",
@@ -1273,7 +1273,7 @@
12731273
{
12741274
"kind": "Interface",
12751275
"canonicalReference": "@google-cloud/functions-framework!InvocationResponse:interface",
1276-
"docComment": "/**\n * InvocationResponse interface describes the properties that can be set on an invocation response.\n */\n",
1276+
"docComment": "/**\n * InvocationResponse interface describes the properties that can be set on an invocation response.\n *\n * @public\n */\n",
12771277
"excerptTokens": [
12781278
{
12791279
"kind": "Content",
@@ -1452,7 +1452,7 @@
14521452
{
14531453
"kind": "Class",
14541454
"canonicalReference": "@google-cloud/functions-framework!JsonInvocationFormat:class",
1455-
"docComment": "/**\n * Default invocation format for JSON requests.\n */\n",
1455+
"docComment": "/**\n * Default invocation format for JSON requests.\n *\n * @public\n */\n",
14561456
"excerptTokens": [
14571457
{
14581458
"kind": "Content",
@@ -1796,7 +1796,7 @@
17961796
{
17971797
"kind": "Variable",
17981798
"canonicalReference": "@google-cloud/functions-framework!typed:var",
1799-
"docComment": "/**\n * Register a function that handles strongly typed invocations.\n *\n * @param functionName - the name of the function\n *\n * @param handler - the function to trigger.\n */\n",
1799+
"docComment": "/**\n * Register a function that handles strongly typed invocations.\n *\n * @param functionName - the name of the function\n *\n * @param handler - the function to trigger.\n *\n * @public\n */\n",
18001800
"excerptTokens": [
18011801
{
18021802
"kind": "Content",
@@ -1808,8 +1808,8 @@
18081808
},
18091809
{
18101810
"kind": "Reference",
1811-
"text": "TypedHandlerFunction",
1812-
"canonicalReference": "@google-cloud/functions-framework!TypedHandlerFunction:interface"
1811+
"text": "TypedFunction",
1812+
"canonicalReference": "@google-cloud/functions-framework!TypedFunction:interface"
18131813
},
18141814
{
18151815
"kind": "Content",
@@ -1836,12 +1836,12 @@
18361836
},
18371837
{
18381838
"kind": "Interface",
1839-
"canonicalReference": "@google-cloud/functions-framework!TypedHandlerFunction:interface",
1840-
"docComment": "/**\n * A Typed function handler that may return a value or a promise.\n */\n",
1839+
"canonicalReference": "@google-cloud/functions-framework!TypedFunction:interface",
1840+
"docComment": "/**\n * A Typed function handler that may return a value or a promise.\n *\n * @public\n */\n",
18411841
"excerptTokens": [
18421842
{
18431843
"kind": "Content",
1844-
"text": "export interface TypedHandlerFunction<T = "
1844+
"text": "export interface TypedFunction<T = "
18451845
},
18461846
{
18471847
"kind": "Content",
@@ -1886,12 +1886,12 @@
18861886
}
18871887
}
18881888
],
1889-
"name": "TypedHandlerFunction",
1889+
"name": "TypedFunction",
18901890
"preserveMemberOrder": false,
18911891
"members": [
18921892
{
18931893
"kind": "PropertySignature",
1894-
"canonicalReference": "@google-cloud/functions-framework!TypedHandlerFunction#format:member",
1894+
"canonicalReference": "@google-cloud/functions-framework!TypedFunction#format:member",
18951895
"docComment": "",
18961896
"excerptTokens": [
18971897
{
@@ -1923,7 +1923,7 @@
19231923
},
19241924
{
19251925
"kind": "PropertySignature",
1926-
"canonicalReference": "@google-cloud/functions-framework!TypedHandlerFunction#handler:member",
1926+
"canonicalReference": "@google-cloud/functions-framework!TypedFunction#handler:member",
19271927
"docComment": "",
19281928
"excerptTokens": [
19291929
{

docs/generated/api.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export interface EventFunctionWithCallback {
5959
}
6060

6161
// @public
62-
export type HandlerFunction<T = unknown, U = unknown> = HttpFunction | EventFunction | EventFunctionWithCallback | CloudEventFunction<T> | CloudEventFunctionWithCallback<T> | TypedHandlerFunction<T, U>;
62+
export type HandlerFunction<T = unknown, U = unknown> = HttpFunction | EventFunction | EventFunctionWithCallback | CloudEventFunction<T> | CloudEventFunctionWithCallback<T> | TypedFunction<T, U>;
6363

6464
// @public
6565
export const http: (functionName: string, handler: HttpFunction) => void;
@@ -72,9 +72,7 @@ export interface HttpFunction {
7272

7373
// @public
7474
export interface InvocationFormat<T, U> {
75-
// (undocumented)
7675
deserializeRequest(request: InvocationRequest): T | Promise<T>;
77-
// (undocumented)
7876
serializeResponse(responseWriter: InvocationResponse, response: U): void | Promise<void>;
7977
}
8078

@@ -121,10 +119,10 @@ export { Request_2 as Request }
121119
export { Response_2 as Response }
122120

123121
// @public
124-
export const typed: <T, U>(functionName: string, handler: TypedHandlerFunction<T, U> | ((req: T) => U | Promise<U>)) => void;
122+
export const typed: <T, U>(functionName: string, handler: TypedFunction<T, U> | ((req: T) => U | Promise<U>)) => void;
125123

126124
// @public
127-
export interface TypedHandlerFunction<T = unknown, U = unknown> {
125+
export interface TypedFunction<T = unknown, U = unknown> {
128126
// (undocumented)
129127
format: InvocationFormat<T, U>;
130128
// (undocumented)

src/function_registry.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
HttpFunction,
1717
CloudEventFunction,
1818
HandlerFunction,
19-
TypedHandlerFunction,
19+
TypedFunction,
2020
JsonInvocationFormat,
2121
} from './functions';
2222
import {SignatureType} from './types';
@@ -104,11 +104,11 @@ export const cloudEvent = <T = unknown>(
104104
/**
105105
* Register a function that handles strongly typed invocations.
106106
* @param functionName - the name of the function
107-
* @param handler - the function to trigger.
107+
* @param handler - the function to trigger
108108
*/
109109
export const typed = <T, U>(
110110
functionName: string,
111-
handler: TypedHandlerFunction<T, U>['handler'] | TypedHandlerFunction<T, U>
111+
handler: TypedFunction<T, U>['handler'] | TypedFunction<T, U>
112112
): void => {
113113
if (handler instanceof Function) {
114114
handler = {

src/function_wrappers.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
CloudEventFunction,
2727
CloudEventFunctionWithCallback,
2828
HandlerFunction,
29-
TypedHandlerFunction,
29+
TypedFunction,
3030
InvocationRequest,
3131
InvocationResponse,
3232
} from './functions';
@@ -206,9 +206,7 @@ const wrapEventFunctionWithCallback = (
206206
* @param userFunction User's function
207207
* @return An Express handler function that invokes the user function
208208
*/
209-
const wrapTypedFunction = (
210-
typedFunction: TypedHandlerFunction
211-
): RequestHandler => {
209+
const wrapTypedFunction = (typedFunction: TypedFunction): RequestHandler => {
212210
class InvocationRequestImpl implements InvocationRequest {
213211
constructor(private req: Request) {}
214212

@@ -298,6 +296,6 @@ export const wrapUserFunction = <T = unknown>(
298296
}
299297
return wrapCloudEventFunction(userFunction as CloudEventFunction);
300298
case 'typed':
301-
return wrapTypedFunction(userFunction as TypedHandlerFunction);
299+
return wrapTypedFunction(userFunction as TypedFunction);
302300
}
303301
};

src/functions.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ export interface CloudEventFunctionWithCallback<T = unknown> {
7777

7878
/**
7979
* A Typed function handler that may return a value or a promise.
80+
* @public
8081
*/
81-
export interface TypedHandlerFunction<T = unknown, U = unknown> {
82+
export interface TypedFunction<T = unknown, U = unknown> {
8283
handler: (req: T) => U | Promise<U>;
8384
format: InvocationFormat<T, U>;
8485
}
@@ -93,7 +94,7 @@ export type HandlerFunction<T = unknown, U = unknown> =
9394
| EventFunctionWithCallback
9495
| CloudEventFunction<T>
9596
| CloudEventFunctionWithCallback<T>
96-
| TypedHandlerFunction<T, U>;
97+
| TypedFunction<T, U>;
9798

9899
/**
99100
* A legacy event.
@@ -150,6 +151,7 @@ export type Context = CloudFunctionsContext | CloudEvent<unknown>;
150151

151152
/**
152153
* InvocationRequest represents the properties of an invocation over HTTP.
154+
* @public
153155
*/
154156
export interface InvocationRequest {
155157
/** Returns the request body as either a string or a Buffer if the body is binary. */
@@ -161,6 +163,7 @@ export interface InvocationRequest {
161163
/**
162164
* InvocationResponse interface describes the properties that can be set on
163165
* an invocation response.
166+
* @public
164167
*/
165168
export interface InvocationResponse {
166169
/** Sets a header on the response. */
@@ -173,18 +176,21 @@ export interface InvocationResponse {
173176

174177
/**
175178
* The contract for a request deserializer and response serializer.
179+
* @public
176180
*/
177181
export interface InvocationFormat<T, U> {
178182
/**
183+
* Creates an instance of the request type from an invocation request.
179184
*
180185
* @param request the request body as raw bytes
181-
* @param headers the headers received on the HTTP request as a map
182186
*/
183187
deserializeRequest(request: InvocationRequest): T | Promise<T>;
188+
184189
/**
190+
* Writes the response type to the invocation result.
185191
*
186-
* @param response
187-
* @param responseHeaders mutable object providing headers that will be set on the response
192+
* @param responseWriter interface for writing to the invocation result
193+
* @param response the response object
188194
*/
189195
serializeResponse(
190196
responseWriter: InvocationResponse,
@@ -194,11 +200,13 @@ export interface InvocationFormat<T, U> {
194200

195201
/**
196202
* Default invocation format for JSON requests.
203+
* @public
197204
*/
198205
export class JsonInvocationFormat<T, U> implements InvocationFormat<T, U> {
199206
deserializeRequest(request: InvocationRequest): T {
200207
const body = request.body();
201208
if (typeof body !== 'string') {
209+
console.log(typeof body);
202210
throw new Error('Unsupported Content-Type, expected application/json');
203211
}
204212
try {

src/server.ts

+9-15
Original file line numberDiff line numberDiff line change
@@ -85,24 +85,18 @@ export function getServer(
8585
};
8686

8787
// Apply middleware
88-
if (functionSignatureType === 'typed') {
89-
app.use(
90-
bodyParser.text({
91-
limit: requestLimit,
92-
type: '*/json',
93-
})
94-
);
95-
app.use(
96-
bodyParser.text({
97-
limit: requestLimit,
98-
type: 'text/*',
99-
})
100-
);
101-
} else {
88+
if (functionSignatureType !== 'typed') {
89+
// If the function is not typed then JSON parsing can be done automatically, otherwise the
90+
// functions format must determine deserialization.
10291
app.use(bodyParser.json(cloudEventsBodySavingOptions));
10392
app.use(bodyParser.json(defaultBodySavingOptions));
104-
app.use(bodyParser.text(defaultBodySavingOptions));
93+
} else {
94+
const jsonParserOptions = Object.assign({}, defaultBodySavingOptions, {
95+
type: 'application/json',
96+
});
97+
app.use(bodyParser.text(jsonParserOptions));
10598
}
99+
app.use(bodyParser.text(defaultBodySavingOptions));
106100
app.use(bodyParser.urlencoded(urlEncodedOptions));
107101
// The parser will process ALL content types so MUST come last.
108102
// Subsequent parsers will be skipped when one is matched.

test/function_registry.ts

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414
import * as assert from 'assert';
1515
import * as FunctionRegistry from '../src/function_registry';
16+
import {JsonInvocationFormat} from '../src';
1617

1718
describe('function_registry', () => {
1819
it('can register http functions', () => {
@@ -31,6 +32,16 @@ describe('function_registry', () => {
3132
assert.deepStrictEqual((userFunction as () => string)(), 'CE_PASS');
3233
});
3334

35+
it('can register typed functions', () => {
36+
FunctionRegistry.typed('typedFunction', (identity: string) => identity);
37+
const {userFunction, signatureType} =
38+
FunctionRegistry.getRegisteredFunction('typedFunction')!;
39+
assert.deepStrictEqual('typed', signatureType);
40+
41+
assert.ok(!(userFunction instanceof Function));
42+
assert.ok(userFunction.format instanceof JsonInvocationFormat);
43+
});
44+
3445
it('throws an error if you try to register a function with an invalid URL', () => {
3546
// Valid function names
3647
const validFunctions = ['httpFunction', 'ceFunction', 'test-func'];

test/function_wrappers.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
Context,
55
CloudEvent,
66
JsonInvocationFormat,
7-
TypedHandlerFunction,
7+
TypedFunction,
88
} from '../src/functions';
99
import {wrapUserFunction} from '../src/function_wrappers';
1010
import EventEmitter = require('events');
@@ -147,10 +147,7 @@ describe('wrapUserFunction', () => {
147147
});
148148

149149
describe('wraps a Typed JSON function', () => {
150-
const synchronousJsonFunction: TypedHandlerFunction<
151-
EchoMessage,
152-
EchoMessage
153-
> = {
150+
const synchronousJsonFunction: TypedFunction<EchoMessage, EchoMessage> = {
154151
format: new JsonInvocationFormat<EchoMessage, EchoMessage>(),
155152
handler: (req: EchoMessage): EchoMessage => {
156153
return {
@@ -200,7 +197,7 @@ describe('wrapUserFunction', () => {
200197
message: 'test',
201198
});
202199

203-
const typedFn: TypedHandlerFunction<EchoMessage, EchoMessage> = {
200+
const typedFn: TypedFunction<EchoMessage, EchoMessage> = {
204201
format: new JsonInvocationFormat<EchoMessage, EchoMessage>(),
205202
handler: (req: EchoMessage): Promise<EchoMessage> => {
206203
return new Promise(accept => {
@@ -231,7 +228,7 @@ describe('wrapUserFunction', () => {
231228
message: 'test',
232229
});
233230

234-
const typedFn: TypedHandlerFunction<EchoMessage, EchoMessage> = {
231+
const typedFn: TypedFunction<EchoMessage, EchoMessage> = {
235232
format: new JsonInvocationFormat<EchoMessage, EchoMessage>(),
236233
handler: (): Promise<EchoMessage> => {
237234
return new Promise((_, reject) => {

test/integration/typed.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ describe('Typed Function', () => {
9797
func: 'nameConcatFunc',
9898
name: 'POST malformatted JSON',
9999
requestBody: 'ASDF',
100-
expectedBody:
101-
'Failed to parse malformatted JSON in request: Unexpected token A in JSON at position 0',
100+
expectedBody: /Failed to parse malformatted JSON in request.*/,
102101
expectedStatus: 400,
103102
expectedCallCount: 0,
104103
},

0 commit comments

Comments
 (0)