mirror of https://github.com/knative/func.git
enhancement(templates): use latest faas-js-runtime + cloudevents (#1422)
* enhancement(templates): use latest faas-js-runtime + cloudevents Better typing of handle functions and return values for typescript based functions. /kind enhancement Signed-off-by: Lance Ball <lball@redhat.com> * fixup: improvements Signed-off-by: Lance Ball <lball@redhat.com> * fixup: missing FUNC_LOG_LEVEL Signed-off-by: Lance Ball <lball@redhat.com> Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
parent
5b032bed66
commit
06693859be
2
Makefile
2
Makefile
|
@ -76,6 +76,8 @@ clean_templates:
|
|||
@rm -rf templates/python/http/__pycache__
|
||||
@rm -rf templates/typescript/cloudevents/node_modules
|
||||
@rm -rf templates/typescript/http/node_modules
|
||||
@rm -rf templates/typescript/cloudevents/build
|
||||
@rm -rf templates/typescript/http/build
|
||||
@rm -rf templates/rust/cloudevents/target
|
||||
@rm -rf templates/rust/http/target
|
||||
@rm -rf templates/quarkus/cloudevents/target
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { CloudEvent, HTTP } = require('cloudevents');
|
||||
const { CloudEvent } = require('cloudevents');
|
||||
|
||||
/**
|
||||
* Your CloudEvent handling function, invoked with each request.
|
||||
|
@ -20,17 +20,14 @@ const { CloudEvent, HTTP } = require('cloudevents');
|
|||
*/
|
||||
const handle = async (context, event) => {
|
||||
// YOUR CODE HERE
|
||||
context.log.info("context");
|
||||
context.log.info(JSON.stringify(context, null, 2));
|
||||
context.log.info("context", context);
|
||||
context.log.info("event", event);
|
||||
|
||||
context.log.info("event");
|
||||
context.log.info(JSON.stringify(event, null, 2));
|
||||
|
||||
return HTTP.binary(new CloudEvent({
|
||||
return new CloudEvent({
|
||||
source: 'event.handler',
|
||||
type: 'echo',
|
||||
data: event
|
||||
}));
|
||||
data: event.data
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { handle };
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,16 +9,16 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "node test/unit.js && node test/integration.js",
|
||||
"start": "faas-js-runtime ./index.js",
|
||||
"start": "FUNC_LOG_LEVEL=info faas-js-runtime ./index.js",
|
||||
"debug": "nodemon --inspect ./node_modules/faas-js-runtime/bin/cli.js ./index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.4",
|
||||
"supertest": "^4.0.2",
|
||||
"supertest": "^6.3.1",
|
||||
"tape": "^4.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cloudevents": "^6.0.2",
|
||||
"faas-js-runtime": "^0.9.1"
|
||||
"cloudevents": "^6.0.3",
|
||||
"faas-js-runtime": "^0.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
'use strict';
|
||||
const { HTTP, CloudEvent } = require('cloudevents');
|
||||
const { start } = require('faas-js-runtime');
|
||||
const request = require('supertest');
|
||||
|
||||
const func = require('..').handle;
|
||||
const test = require('tape');
|
||||
|
||||
const Spec = {
|
||||
version: 'ce-specversion',
|
||||
type: 'ce-type',
|
||||
id: 'ce-id',
|
||||
source: 'ce-source'
|
||||
};
|
||||
|
||||
const data = {
|
||||
name: 'tiger',
|
||||
customerId: '01234'
|
||||
|
@ -22,22 +16,25 @@ const errHandler = t => err => {
|
|||
t.end();
|
||||
};
|
||||
|
||||
const message = HTTP.binary(new CloudEvent({
|
||||
type: 'com.example.test',
|
||||
source: 'http://localhost:8080',
|
||||
data
|
||||
}));
|
||||
|
||||
test('Integration: handles a valid event', t => {
|
||||
start(func).then(server => {
|
||||
t.plan(5);
|
||||
request(server)
|
||||
.post('/')
|
||||
.send(data)
|
||||
.set(Spec.id, '01234')
|
||||
.set(Spec.source, '/test')
|
||||
.set(Spec.type, 'com.example.cloudevents.test')
|
||||
.set(Spec.version, '1.0')
|
||||
.send(message.body)
|
||||
.set(message.headers)
|
||||
.expect(200)
|
||||
.expect('Content-Type', /json/)
|
||||
.end((err, result) => {
|
||||
t.error(err, 'No error');
|
||||
t.ok(result);
|
||||
t.deepEqual(result.body.data, data);
|
||||
t.deepEqual(result.body, data);
|
||||
t.equal(result.headers['ce-type'], 'echo');
|
||||
t.equal(result.headers['ce-source'], 'event.handler');
|
||||
t.end();
|
||||
|
|
|
@ -11,6 +11,7 @@ test('Unit: handles a valid event', async t => {
|
|||
name: 'tiger',
|
||||
customerId: '01234'
|
||||
}
|
||||
|
||||
// A valid event includes id, type and source at a minimum.
|
||||
const cloudevent = new CloudEvent({
|
||||
id: '01234',
|
||||
|
@ -19,30 +20,11 @@ test('Unit: handles a valid event', async t => {
|
|||
data
|
||||
});
|
||||
|
||||
const mockContext = new MockContext(cloudevent);
|
||||
|
||||
// Invoke the function with the valid event, which should complete without error.
|
||||
const result = await func(mockContext, data);
|
||||
const result = await func({ log: { info: (_) => _ } }, cloudevent);
|
||||
t.ok(result);
|
||||
t.equal(result.body, JSON.stringify(data));
|
||||
t.equal(result.headers['ce-type'], 'echo');
|
||||
t.equal(result.headers['ce-source'], 'event.handler');
|
||||
t.equal(result.data, data);
|
||||
t.equal(result.type, 'echo');
|
||||
t.equal(result.source, 'event.handler');
|
||||
t.end();
|
||||
});
|
||||
|
||||
class MockContext {
|
||||
cloudevent;
|
||||
|
||||
constructor(cloudevent) {
|
||||
this.cloudevent = cloudevent;
|
||||
this.log = { info: console.log, debug: console.debug }
|
||||
}
|
||||
|
||||
cloudEventResponse(data) {
|
||||
return new CloudEvent({
|
||||
data,
|
||||
type: 'com.example.cloudevents.test.response',
|
||||
source: '/test'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,18 +15,17 @@
|
|||
* @param {string} context.httpVersion the HTTP protocol version
|
||||
* See: https://github.com/knative/func/blob/main/docs/function-developers/nodejs.md#the-context-object
|
||||
*/
|
||||
const handle = async (context) => {
|
||||
const handle = async (context, body) => {
|
||||
// YOUR CODE HERE
|
||||
context.log.info(JSON.stringify(context, null, 2));
|
||||
context.log.info("query", context.query);
|
||||
context.log.info("body", body);
|
||||
|
||||
// If the request is an HTTP POST, the context will contain the request body
|
||||
if (context.method === 'POST') {
|
||||
return {
|
||||
body: context.body,
|
||||
}
|
||||
// If the request is an HTTP GET, the context will include a query string, if it exists
|
||||
return { body };
|
||||
} else if (context.method === 'GET') {
|
||||
return {
|
||||
// If the request is an HTTP GET, the context will include a query string, if it exists
|
||||
return {
|
||||
query: context.query,
|
||||
}
|
||||
} else {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,18 +5,18 @@
|
|||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "node test/unit.js && node test/integration.js",
|
||||
"start": "faas-js-runtime ./index.js",
|
||||
"start": "FUNC_LOG_LEVEL=info faas-js-runtime ./index.js",
|
||||
"debug": "nodemon --inspect ./node_modules/faas-js-runtime/bin/cli.js ./index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"faas-js-runtime": "^0.9.1"
|
||||
"faas-js-runtime": "^0.9.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.4",
|
||||
"supertest": "^4.0.2",
|
||||
"supertest": "^6.3.1",
|
||||
"tape": "^5.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ test('Unit: handles an HTTP GET', async t => {
|
|||
|
||||
test('Unit: handles an HTTP POST', async t => {
|
||||
t.plan(1);
|
||||
const body = { name: 'tiger' };
|
||||
// Invoke the function, which should complete without error.
|
||||
const result = await func({ ...fixture, method: 'POST', body: { name: 'tiger' } });
|
||||
t.deepEqual(result, { body: { name: 'tiger' } });
|
||||
const result = await func({ ...fixture, method: 'POST', body }, body);
|
||||
t.deepEqual(result, { body });
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
"semi": true,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
"printWidth": 125
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,7 @@
|
|||
"test:unit": "ts-node node_modules/tape/bin/tape test/unit.ts",
|
||||
"test:integration": "ts-node node_modules/tape/bin/tape test/integration.ts",
|
||||
"test": "npm run test:unit && npm run test:integration",
|
||||
"start": "faas-js-runtime ./build/index.js",
|
||||
"start": "FUNC_LOG_LEVEL=info faas-js-runtime ./build/index.js",
|
||||
"lint": "eslint \"src/**/*.{js,ts,tsx}\" \"test/**/*.{js,ts,tsx}\" --quiet",
|
||||
"debug": "nodemon --inspect ./node_modules/faas-js-runtime/bin/cli.js ./build/index.js"
|
||||
},
|
||||
|
@ -26,15 +26,16 @@
|
|||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"nodemon": "^2.0.4",
|
||||
"prettier": "^2.3.0",
|
||||
"supertest": "^4.0.2",
|
||||
"supertest": "^6.3.1",
|
||||
"tape": "^4.13.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"tsd": "^0.24.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^16.11.12",
|
||||
"cloudevents": "^6.0.2",
|
||||
"faas-js-runtime": "^0.9.1"
|
||||
"cloudevents": "^6.0.3",
|
||||
"faas-js-runtime": "^0.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CloudEvent, HTTP, Message } from 'cloudevents';
|
||||
import { CloudEvent } from 'cloudevents';
|
||||
import { Context } from 'faas-js-runtime';
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,8 @@ import { Context } from 'faas-js-runtime';
|
|||
* See: https://github.com/knative/func/blob/main/docs/guides/nodejs.md#the-context-object
|
||||
* @param {CloudEvent} cloudevent the CloudEvent
|
||||
*/
|
||||
const handle = async (_: Context, cloudevent?: CloudEvent<unknown>): Promise<Message> => {
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
const handle = async (context: Context, cloudevent?: CloudEvent<Customer>): Promise<CloudEvent<Customer|string>> => {
|
||||
// YOUR CODE HERE
|
||||
const meta = {
|
||||
source: 'function.eventViewer',
|
||||
|
@ -31,10 +32,10 @@ const handle = async (_: Context, cloudevent?: CloudEvent<unknown>): Promise<Mes
|
|||
...meta,
|
||||
...{ type: 'error', data: 'No event received' }
|
||||
});
|
||||
console.log(response.toString());
|
||||
return HTTP.binary(response);
|
||||
context.log.info(response.toString());
|
||||
return response;
|
||||
}
|
||||
console.log(`
|
||||
context.log.info(`
|
||||
-----------------------------------------------------------
|
||||
CloudEvent:
|
||||
${cloudevent}
|
||||
|
@ -44,7 +45,12 @@ ${JSON.stringify(cloudevent.data)}
|
|||
-----------------------------------------------------------
|
||||
`);
|
||||
// respond with a new CloudEvent
|
||||
return HTTP.binary(new CloudEvent({ ...meta, data: cloudevent.data }));
|
||||
return new CloudEvent<Customer>({ ...meta, data: cloudevent.data });
|
||||
};
|
||||
|
||||
export interface Customer {
|
||||
name: string;
|
||||
customerId: string;
|
||||
}
|
||||
|
||||
export { handle };
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
import test from 'tape';
|
||||
import { expectType } from 'tsd';
|
||||
import { CloudEvent } from 'cloudevents';
|
||||
import { Context } from 'faas-js-runtime';
|
||||
import { handle } from '../src';
|
||||
|
||||
// Test typed CloudEvent data
|
||||
interface Customer {
|
||||
name: string;
|
||||
customerId: string;
|
||||
}
|
||||
import { CloudEventFunction, Context } from 'faas-js-runtime';
|
||||
import { handle, Customer } from '../src';
|
||||
|
||||
// Ensure that the function completes cleanly when passed a valid event.
|
||||
test('Unit: handles a valid event', async (t) => {
|
||||
|
@ -18,6 +13,7 @@ test('Unit: handles a valid event', async (t) => {
|
|||
name: 'tiger',
|
||||
customerId: '01234'
|
||||
};
|
||||
|
||||
// A valid event includes id, type and source at a minimum.
|
||||
const cloudevent: CloudEvent<Customer> = new CloudEvent({
|
||||
id: '01234',
|
||||
|
@ -27,11 +23,13 @@ test('Unit: handles a valid event', async (t) => {
|
|||
});
|
||||
|
||||
// Invoke the function with the valid event, which should complete without error.
|
||||
const result = await handle({} as Context, cloudevent);
|
||||
const result = await handle({ log: { info: (_) => _ } } as Context, cloudevent);
|
||||
t.ok(result);
|
||||
t.deepEqual(JSON.parse(result.body as string), data);
|
||||
console.log(result);
|
||||
t.equal(result.headers['ce-type'], 'echo');
|
||||
t.equal(result.headers['ce-source'], 'function.eventViewer');
|
||||
t.deepEqual(result.data, data);
|
||||
t.equal(result.type, 'echo');
|
||||
t.equal(result.source, 'function.eventViewer');
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Ensure that the handle function is typed correctly.
|
||||
expectType<CloudEventFunction>(handle);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,7 @@
|
|||
"test:unit": "ts-node node_modules/tape/bin/tape test/unit.ts",
|
||||
"test:integration": "ts-node node_modules/tape/bin/tape test/integration.ts",
|
||||
"test": "npm run test:unit && npm run test:integration",
|
||||
"start": "faas-js-runtime ./build/index.js",
|
||||
"start": "FUNC_LOG_LEVEL=info faas-js-runtime ./build/index.js",
|
||||
"lint": "eslint \"src/**/*.{js,ts,tsx}\" \"test/**/*.{js,ts,tsx}\" --quiet",
|
||||
"debug": "nodemon --inspect ./node_modules/faas-js-runtime/bin/cli.js ./build/index.js"
|
||||
},
|
||||
|
@ -26,14 +26,15 @@
|
|||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"nodemon": "^2.0.4",
|
||||
"prettier": "^2.3.0",
|
||||
"supertest": "^4.0.2",
|
||||
"supertest": "^6.3.1",
|
||||
"tape": "^4.13.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"tsd": "^0.24.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^16.11.12",
|
||||
"faas-js-runtime": "^0.9.1"
|
||||
"faas-js-runtime": "^0.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Context } from 'faas-js-runtime';
|
||||
import { Context, StructuredReturn } from 'faas-js-runtime';
|
||||
|
||||
/**
|
||||
* Your HTTP handling function, invoked with each request. This is an example
|
||||
|
@ -19,10 +19,9 @@ import { Context } from 'faas-js-runtime';
|
|||
* @param {string} context.httpVersion the HTTP protocol version
|
||||
* See: https://github.com/knative/func/blob/main/docs/guides/nodejs.md#the-context-object
|
||||
*/
|
||||
export const handle = async (context: Context): Promise<string> => {
|
||||
export const handle = async (context: Context, body: string): Promise<StructuredReturn> => {
|
||||
// YOUR CODE HERE
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`
|
||||
context.log.info(`
|
||||
-----------------------------------------------------------
|
||||
Headers:
|
||||
${JSON.stringify(context.headers)}
|
||||
|
@ -31,8 +30,13 @@ Query:
|
|||
${JSON.stringify(context.query)}
|
||||
|
||||
Body:
|
||||
${JSON.stringify(context.body)}
|
||||
${JSON.stringify(body)}
|
||||
-----------------------------------------------------------
|
||||
`);
|
||||
return JSON.stringify(context.body);
|
||||
return {
|
||||
body: body,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
import test from 'tape';
|
||||
import { Context } from 'faas-js-runtime';
|
||||
import * as func from '../build/index.js';
|
||||
import { expectType } from 'tsd';
|
||||
import { Context, HTTPFunction } from 'faas-js-runtime';
|
||||
import { handle } from '../build/index.js';
|
||||
|
||||
// Ensure that the function completes cleanly when passed a valid event.
|
||||
test('Unit: handles a valid request', async (t) => {
|
||||
|
@ -12,12 +13,12 @@ test('Unit: handles a valid request', async (t) => {
|
|||
customerId: '01234'
|
||||
};
|
||||
|
||||
const handle = func.handle;
|
||||
const mockContext = { body } as Context;
|
||||
|
||||
// Invoke the function which should complete without error and echo the data
|
||||
const result = await handle(mockContext);
|
||||
const result = await handle({ log: { info: (_) => _ } } as Context, body);
|
||||
t.ok(result);
|
||||
t.equal(result, JSON.stringify(body));
|
||||
t.equal(result.body, body);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Ensure that the handle function is typed correctly.
|
||||
expectType<HTTPFunction>(handle);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue