Skip to content

Commit 862b4b2

Browse files
committed
chore(refactor): protocol bindings use interfaces
This change modifies the protocol binding interfaces such as `Binding`, `Serializer` and the like to use the `CloudEventV1` interface instead of the implementation class `CloudEvent`. This should make extending the interfaces simpler as this work has grown out of efforts around the implementation of a second transport interface, Kafka. See: cloudevents#455 This commit also includes the addition of a generic type to the `Message` interface, defaulting to `string`. There is also some minor clean up involving what is exported from the `message/http` modules. Now, instead of exporting the entire implementation, only the `HTTP` binding implementation is exported, and it is then reexported by `message`. Also, a static `CloudEvent.cloneWith()` method has been added which the instance methods now use. Signed-off-by: Lance Ball <[email protected]>
1 parent 834beae commit 862b4b2

File tree

10 files changed

+219
-164
lines changed

10 files changed

+219
-164
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
"lint:js": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' cucumber.js",
1111
"lint:md": "remark .",
1212
"lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix",
13-
"apretest": "npm run lint && npm run conformance",
14-
"test": "mocha --require ts-node/register ./test/integration/**/kafka_tests.ts",
15-
"conformance": "cucumber-js ./conformance/features/http-protocol-binding.feature -p default",
13+
"pretest": "npm run lint && npm run conformance",
14+
"test": "mocha --require ts-node/register ./test/integration/**/*.ts",
15+
"conformance": "cucumber-js ./conformance/features/*-protocol-binding.feature -p default",
1616
"coverage": "nyc --reporter=lcov --reporter=text npm run test",
1717
"coverage-publish": "wget -qO - https://coverage.codacy.com/get.sh | bash -s report -l JavaScript -r coverage/lcov.info",
1818
"generate-docs": "typedoc --excludeNotDocumented --out docs src",

src/event/cloudevent.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
198198
* @throws if the CloudEvent does not conform to the schema
199199
* @return {CloudEvent} returns a new CloudEvent<D>
200200
*/
201-
public cloneWith<D>(options: Partial<CloudEvent<D>>, strict?: boolean): CloudEvent<D>;
201+
public cloneWith<D>(options: Partial<CloudEventV1<D>>, strict?: boolean): CloudEvent<D>;
202202
/**
203203
* Clone a CloudEvent with new/update attributes
204204
* @param {object} options attributes to augment the CloudEvent
@@ -207,7 +207,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
207207
* @return {CloudEvent} returns a new CloudEvent
208208
*/
209209
public cloneWith<D>(options: Partial<CloudEventV1<D>>, strict = true): CloudEvent<D | T> {
210-
return new CloudEvent(Object.assign({}, this.toJSON(), options), strict);
210+
return CloudEvent.cloneWith(this as CloudEvent<T>, options, strict);
211211
}
212212

213213
/**
@@ -217,4 +217,11 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
217217
[Symbol.for("nodejs.util.inspect.custom")](): string {
218218
return this.toString();
219219
}
220+
221+
public static cloneWith(
222+
event: CloudEvent<any>, // Must be a concrete CloudEvent class
223+
options: Partial<CloudEventV1<any>>, // May take any
224+
strict = true): CloudEvent<any> {
225+
return new CloudEvent(Object.assign({}, event.toJSON(), options), strict);
226+
}
220227
}

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import { ValidationError } from "./event/validation";
88
import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces";
99

1010
import { Options, TransportFunction, EmitterFunction, emitterFor, Emitter } from "./transport/emitter";
11-
import { Headers, Mode, Binding, HTTP, Message, Serializer, Deserializer } from "./message";
11+
import {
12+
Headers, Mode, Binding, HTTP, Kafka, KafkaEvent, KafkaMessage, Message,
13+
Serializer, Deserializer } from "./message";
1214

1315
import CONSTANTS from "./constants";
1416

@@ -27,6 +29,9 @@ export {
2729
Deserializer,
2830
Serializer,
2931
HTTP,
32+
Kafka,
33+
KafkaEvent,
34+
KafkaMessage,
3035
// From transport
3136
TransportFunction,
3237
EmitterFunction,

src/message/http/headers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { PassThroughParser, DateParser, MappedParser } from "../../parsers";
7-
import { CloudEvent } from "../..";
7+
import { CloudEventV1 } from "../..";
88
import { Headers } from "../";
99
import { Version } from "../../event/cloudevent";
1010
import CONSTANTS from "../../constants";
@@ -24,7 +24,7 @@ export const requiredHeaders = [
2424
* @param {CloudEvent} event a CloudEvent
2525
* @returns {Object} the headers that will be sent for the event
2626
*/
27-
export function headersFor<T>(event: CloudEvent<T>): Headers {
27+
export function headersFor<T>(event: CloudEventV1<T>): Headers {
2828
const headers: Headers = {};
2929
let headerMap: Readonly<{ [key: string]: MappedParser }>;
3030
if (event.specversion === Version.V1) {

src/message/http/index.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { CloudEvent, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
7-
import { Message, Headers } from "..";
7+
import { Message, Headers, Binding } from "..";
88

99
import {
1010
headersFor,
@@ -25,7 +25,7 @@ import { JSONParser, MappedParser, Parser, parserByContentType } from "../../par
2525
* @param {CloudEvent} event The event to serialize
2626
* @returns {Message} a Message object with headers and body
2727
*/
28-
export function binary<T>(event: CloudEvent<T>): Message {
28+
function binary<T>(event: CloudEventV1<T>): Message {
2929
const contentType: Headers = { [CONSTANTS.HEADER_CONTENT_TYPE]: CONSTANTS.DEFAULT_CONTENT_TYPE };
3030
const headers: Headers = { ...contentType, ...headersFor(event) };
3131
let body = event.data;
@@ -47,10 +47,10 @@ export function binary<T>(event: CloudEvent<T>): Message {
4747
* @param {CloudEvent} event the CloudEvent to be serialized
4848
* @returns {Message} a Message object with headers and body
4949
*/
50-
export function structured<T>(event: CloudEvent<T>): Message {
50+
function structured<T>(event: CloudEventV1<T>): Message {
5151
if (event.data_base64) {
5252
// The event's data is binary - delete it
53-
event = event.cloneWith({ data: undefined });
53+
event = (event as CloudEvent).cloneWith({ data: undefined });
5454
}
5555
return {
5656
headers: {
@@ -67,7 +67,7 @@ export function structured<T>(event: CloudEvent<T>): Message {
6767
* @param {Message} message an incoming Message object
6868
* @returns {boolean} true if this Message is a CloudEvent
6969
*/
70-
export function isEvent(message: Message): boolean {
70+
function isEvent(message: Message): boolean {
7171
// TODO: this could probably be optimized
7272
try {
7373
deserialize(message);
@@ -84,7 +84,7 @@ export function isEvent(message: Message): boolean {
8484
* @param {Message} message the incoming message
8585
* @return {CloudEvent} A new {CloudEvent} instance
8686
*/
87-
export function deserialize<T>(message: Message): CloudEvent<T> | CloudEvent<T>[] {
87+
function deserialize<T>(message: Message): CloudEvent<T> | CloudEvent<T>[] {
8888
const cleanHeaders: Headers = sanitize(message.headers);
8989
const mode: Mode = getMode(cleanHeaders);
9090
const version = getVersion(mode, cleanHeaders, message.body);
@@ -261,3 +261,14 @@ function parseBatched<T>(message: Message): CloudEvent<T> | CloudEvent<T>[] {
261261
});
262262
return ret;
263263
}
264+
265+
/**
266+
* Bindings for HTTP transport support
267+
* @implements {@linkcode Binding}
268+
*/
269+
export const HTTP: Binding = {
270+
binary,
271+
structured,
272+
toEvent: deserialize,
273+
isEvent: isEvent,
274+
};

src/message/index.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
*/
55

66
import { IncomingHttpHeaders } from "http";
7-
import { CloudEvent } from "..";
8-
import { binary, deserialize, structured, isEvent } from "./http";
7+
import { CloudEventV1 } from "..";
8+
9+
// reexport the protocol bindings
10+
export * from "./http";
11+
export * from "./kafka";
912

1013
/**
1114
* Binding is an interface for transport protocols to implement,
@@ -62,7 +65,7 @@ export enum Mode {
6265
* @interface
6366
*/
6467
export interface Serializer {
65-
<T>(event: CloudEvent<T>): Message;
68+
<T>(event: CloudEventV1<T>): Message;
6669
}
6770

6871
/**
@@ -71,7 +74,7 @@ export interface Serializer {
7174
* @interface
7275
*/
7376
export interface Deserializer {
74-
<T>(message: Message): CloudEvent<T> | CloudEvent<T>[];
77+
<T>(message: Message): CloudEventV1<T> | CloudEventV1<T>[];
7578
}
7679

7780
/**
@@ -82,16 +85,3 @@ export interface Deserializer {
8285
export interface Detector {
8386
(message: Message): boolean;
8487
}
85-
86-
/**
87-
* Bindings for HTTP transport support
88-
* @implements {@linkcode Binding}
89-
*/
90-
export const HTTP: Binding = {
91-
binary: binary as Serializer,
92-
structured: structured as Serializer,
93-
toEvent: deserialize as Deserializer,
94-
isEvent: isEvent as Detector,
95-
};
96-
97-
export * from "./kafka";

src/message/kafka/headers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { CloudEvent, CONSTANTS, Headers } from "../..";
6+
import { CloudEventV1, CONSTANTS, Headers } from "../..";
77

88
type KafkaHeaders = Readonly<{
99
ID: string;
@@ -55,7 +55,7 @@ export const HEADER_MAP: { [key: string]: string } = {
5555
* @param {CloudEvent} event a CloudEvent object
5656
* @returns {Headers} the CloudEvent attribute as Kafka headers
5757
*/
58-
export function headersFor<T>(event: CloudEvent<T>): Headers {
58+
export function headersFor<T>(event: CloudEventV1<T>): Headers {
5959
const headers: Headers = {};
6060

6161
Object.getOwnPropertyNames(event).forEach((property) => {

0 commit comments

Comments
 (0)