feat: expose a mode and version agnostic event receiver (#120)
Event receivers in the wild may not always know what version or mode an incoming event is. Instead of requiring developers to inspect the headers themselves, the SDK should provide an HTTP receiver that is capable of figuring out what the version and mode (structured/binary) of an incoming event is and handle it appropriately. In determining the best way to expose this, I chose to modify the API a little bit. Now, instead of `const CloudEvent = require('cloudevents-sdk');` users need to destructure it. ```js const { HTTPReceiver, CloudEvent } = require('cloudevents-sdk'); ``` This change should not be backported to 1.x. Fixes: https://github.com/cloudevents/sdk-javascript/issues/93 Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
parent
d9e9ae6bdc
commit
54f242b79e
6
index.js
6
index.js
|
@ -1,3 +1,7 @@
|
|||
const CloudEvent = require("./lib/cloudevent.js");
|
||||
const HTTPReceiver = require("./lib/bindings/http/http_receiver.js");
|
||||
|
||||
module.exports = CloudEvent;
|
||||
module.exports = {
|
||||
CloudEvent,
|
||||
HTTPReceiver
|
||||
};
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
const V03Binary = require("./receiver_binary_0_3");
|
||||
const V03Structured = require("./receiver_structured_0_3.js");
|
||||
const V1Binary = require("./receiver_binary_1.js");
|
||||
const V1Structured = require("./receiver_structured_1.js");
|
||||
const constants = require("./constants");
|
||||
|
||||
class HTTPReceiver {
|
||||
constructor() {
|
||||
this.receivers = {
|
||||
v1: {
|
||||
structured: new V1Structured(),
|
||||
binary: new V1Binary()
|
||||
},
|
||||
v03: {
|
||||
structured: new V03Structured(),
|
||||
binary: new V03Binary()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
accept(headers, body) {
|
||||
const mode = getMode(headers);
|
||||
const version = getVersion(mode, headers, body);
|
||||
switch (version) {
|
||||
case constants.SPEC_V1:
|
||||
return this.receivers.v1[mode].parse(body, headers);
|
||||
case constants.SPEC_V03:
|
||||
return this.receivers.v03[mode].parse(body, headers);
|
||||
default:
|
||||
console.error(
|
||||
`Unknown spec version ${version}. Default to ${constants.SPEC_V1}`);
|
||||
return this.receivers.v1[mode].parse(body, headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMode(headers) {
|
||||
let mode = "binary";
|
||||
const contentType = headers[constants.HEADER_CONTENT_TYPE];
|
||||
if (contentType && contentType.startsWith(constants.MIME_CE)) {
|
||||
mode = "structured";
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
function getVersion(mode, headers, body) {
|
||||
let version = constants.SPEC_V1; // default to 1.0
|
||||
|
||||
if (mode === "binary") {
|
||||
// Check the headers for the version
|
||||
const versionHeader = headers[constants.DEFAULT_SPEC_VERSION_HEADER];
|
||||
if (versionHeader) { version = versionHeader; }
|
||||
} else {
|
||||
// structured mode - the version is in the body
|
||||
version = body instanceof String
|
||||
? JSON.parse(body).specversion : body.specversion;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
module.exports = HTTPReceiver;
|
|
@ -0,0 +1,90 @@
|
|||
const { expect } = require("chai");
|
||||
const { CloudEvent, HTTPReceiver } = require("../../../index.js");
|
||||
const constants = require("../../../lib/bindings/http/constants.js");
|
||||
|
||||
const receiver = new HTTPReceiver();
|
||||
const id = "1234";
|
||||
const type = "org.cncf.cloudevents.test";
|
||||
const source = "urn:event:from:myapi/resourse/123";
|
||||
const data = {
|
||||
lunch: "sushi"
|
||||
};
|
||||
|
||||
describe("HTTP Transport Binding Receiver for CloudEvents", () => {
|
||||
describe("V1", () => {
|
||||
const specversion = "1.0";
|
||||
|
||||
it("Structured data returns a CloudEvent", () => {
|
||||
const payload = {
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
data,
|
||||
specversion
|
||||
};
|
||||
|
||||
const headers = {
|
||||
[constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON
|
||||
};
|
||||
|
||||
const event = receiver.accept(headers, payload);
|
||||
validateEvent(event, specversion);
|
||||
});
|
||||
|
||||
it("Binary data returns a CloudEvent", () => {
|
||||
const headers = {
|
||||
[constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE,
|
||||
[constants.DEFAULT_SPEC_VERSION_HEADER]: specversion,
|
||||
[constants.BINARY_HEADERS_1.ID]: id,
|
||||
[constants.BINARY_HEADERS_1.TYPE]: type,
|
||||
[constants.BINARY_HEADERS_1.SOURCE]: source
|
||||
};
|
||||
|
||||
const event = receiver.accept(headers, data);
|
||||
validateEvent(event, specversion);
|
||||
});
|
||||
});
|
||||
|
||||
describe("V03", () => {
|
||||
const specversion = "0.3";
|
||||
|
||||
it("Structured data returns a CloudEvent", () => {
|
||||
const payload = {
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
data,
|
||||
specversion
|
||||
};
|
||||
|
||||
const headers = {
|
||||
[constants.HEADER_CONTENT_TYPE]: constants.MIME_CE_JSON
|
||||
};
|
||||
|
||||
const event = receiver.accept(headers, payload);
|
||||
validateEvent(event, specversion);
|
||||
});
|
||||
|
||||
it("Binary data returns a CloudEvent", () => {
|
||||
const headers = {
|
||||
[constants.HEADER_CONTENT_TYPE]: constants.DEFAULT_CONTENT_TYPE,
|
||||
[constants.DEFAULT_SPEC_VERSION_HEADER]: specversion,
|
||||
[constants.BINARY_HEADERS_03.ID]: id,
|
||||
[constants.BINARY_HEADERS_03.TYPE]: type,
|
||||
[constants.BINARY_HEADERS_03.SOURCE]: source
|
||||
};
|
||||
|
||||
const event = receiver.accept(headers, data);
|
||||
validateEvent(event, specversion);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function validateEvent(event, specversion) {
|
||||
expect(event instanceof CloudEvent).to.equal(true);
|
||||
expect(event.getId()).to.equal(id);
|
||||
expect(event.getType()).to.equal(type);
|
||||
expect(event.getSource()).to.equal(source);
|
||||
expect(event.getData()).to.deep.equal(data);
|
||||
expect(event.getSpecversion()).to.equal(specversion);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
const expect = require("chai").expect;
|
||||
const v1 = require("../../../v1/index.js");
|
||||
const CloudEvent = require("../../../index.js");
|
||||
const { CloudEvent } = require("../../../index.js");
|
||||
|
||||
const { asBase64 } = require("../../../lib/utils/fun.js");
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const expect = require("chai").expect;
|
||||
const Unmarshaller = require("../../../lib/bindings/http/unmarshaller_0_3.js");
|
||||
const CloudEvent = require("../../../index.js");
|
||||
const { CloudEvent } = require("../../../index.js");
|
||||
const v03 = require("../../../v03/index.js");
|
||||
|
||||
const type = "com.github.pull.create";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const expect = require("chai").expect;
|
||||
const Spec03 = require("../lib/specs/spec_0_3.js");
|
||||
const CloudEvent = require("../index.js");
|
||||
const { CloudEvent } = require("../index.js");
|
||||
const { v4: uuidv4 } = require("uuid");
|
||||
|
||||
const id = uuidv4();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const expect = require("chai").expect;
|
||||
const Spec1 = require("../lib/specs/spec_1.js");
|
||||
const CloudEvent = require("../index.js");
|
||||
const { CloudEvent } = require("../index.js");
|
||||
const { v4: uuidv4 } = require("uuid");
|
||||
const { asBase64 } = require("../lib/utils/fun.js");
|
||||
|
||||
|
|
Loading…
Reference in New Issue