Skip to content

Commit

Permalink
feat: Allow simple JSON for event payloads (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjholm authored Apr 30, 2023
2 parents 04df14c + b23bf81 commit 4ca1864
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 47 deletions.
18 changes: 6 additions & 12 deletions src/api/events/v0/events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
TopicServiceClient as GrpcTopicServiceClient,
} from '@nitric/api/proto/event/v1/event_grpc_pb';
import { UnimplementedError } from '../../errors';
import { NitricEvent } from '@nitric/sdk/types';

describe('Event Client Tests', () => {
describe('Given nitric.interfaces.event.EventServiceClient.publish throws an error', () => {
Expand Down Expand Up @@ -84,19 +85,12 @@ describe('Event Client Tests', () => {

test('Then Eventing.publish should resolve with the provided id', async () => {
const client = new Eventing();
const event = new NitricEvent({ test: 'test' }, 'test', 'Test Payload');
await expect(
client.topic('test').publish({
id: 'test',
payloadType: 'Test Payload',
payload: {
test: 'test',
},
})
).resolves.toStrictEqual({
id: 'test',
payload: { test: 'test' },
payloadType: 'Test Payload',
});
client
.topic('test')
.publish(new NitricEvent({ test: 'test' }, 'test', 'Test Payload'))
).resolves.toStrictEqual(event);
});

test('The Grpc client for Eventing.publish should have been called exactly once', () => {
Expand Down
32 changes: 21 additions & 11 deletions src/api/events/v0/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@nitric/api/proto/event/v1/event_pb';
import { Struct } from 'google-protobuf/google/protobuf/struct_pb';
import * as grpc from '@grpc/grpc-js';
import type { NitricEvent } from '../../../types';
import { NitricEvent } from '../../../types';
import { fromGrpcError, InvalidArgumentError } from '../../errors';

/**
Expand Down Expand Up @@ -51,7 +51,7 @@ const DEFAULT_PUBLISH_OPTS: PublishOptions = {
delay: 0,
};

export class Topic<T extends NitricEvent = NitricEvent> {
export class Topic<T extends Record<string, any> = Record<string, any>> {
eventing: Eventing;
name: string;

Expand Down Expand Up @@ -90,31 +90,39 @@ export class Topic<T extends NitricEvent = NitricEvent> {
* ```
*/
async publish(
event: T,
event: T | NitricEvent<T>,
opts: PublishOptions = DEFAULT_PUBLISH_OPTS
): Promise<T> {
const { id, payloadType = 'none', payload } = event;
): Promise<NitricEvent<T>> {
const nitricEvent =
event instanceof NitricEvent ? event : new NitricEvent(event);

const publishOpts = {
...DEFAULT_PUBLISH_OPTS,
...opts,
};
const request = new EventPublishRequest();
const evt = new PbEvent();

evt.setId(id);
evt.setPayload(Struct.fromJavaScript(payload));
evt.setPayloadType(payloadType);
evt.setId(nitricEvent.id);
evt.setPayload(Struct.fromJavaScript(nitricEvent.payload));
evt.setPayloadType(nitricEvent.payloadType);

request.setTopic(this.name);
request.setEvent(evt);
request.setDelay(publishOpts.delay);

return new Promise<T>((resolve, reject) => {
return new Promise<NitricEvent<T>>((resolve, reject) => {
this.eventing.EventServiceClient.publish(request, (error, response) => {
if (error) {
reject(fromGrpcError(error));
} else {
resolve({ ...event, id: response.getId() });
resolve(
new NitricEvent(
nitricEvent.payload,
response.getId(),
nitricEvent.payloadType
)
);
}
});
});
Expand Down Expand Up @@ -167,7 +175,9 @@ export class Eventing {
* const topic = eventing.topic('notifications');
* ```
*/
public topic<T extends NitricEvent = NitricEvent>(name: string): Topic<T> {
public topic<T extends Record<string, any> = Record<string, any>>(
name: string
): Topic<T> {
if (!name) {
throw new InvalidArgumentError('A topic name is needed to use a Topic.');
}
Expand Down
5 changes: 3 additions & 2 deletions src/faas/v0/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ export type GenericMiddleware<Ctx> = (

export type TriggerMiddleware = GenericMiddleware<TriggerContext>;
export type HttpMiddleware = GenericMiddleware<HttpContext>;
export type EventMiddleware<T extends NitricEvent = NitricEvent> =
GenericMiddleware<EventContext<T>>;
export type EventMiddleware<
T extends Record<string, any> = Record<string, any>
> = GenericMiddleware<EventContext<NitricEvent<T>>>;
export type ScheduleMiddleware = GenericMiddleware<EventContext<undefined>>;

/**
Expand Down
4 changes: 2 additions & 2 deletions src/resources/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class SubscriptionWorkerOptions {
/**
* Creates a subscription worker
*/
class Subscription<T extends NitricEvent = NitricEvent> {
class Subscription<T extends Record<string, any> = Record<string, any>> {
private readonly faas: Faas;

constructor(name: string, ...mw: EventMiddleware<T>[]) {
Expand All @@ -55,7 +55,7 @@ class Subscription<T extends NitricEvent = NitricEvent> {
* Topic resource for pub/sub async messaging.
*/
export class TopicResource<
T extends NitricEvent = NitricEvent
T extends Record<string, any> = Record<string, any>
> extends SecureResource<TopicPermission> {
/**
* Register this topic as a required resource for the calling function/container
Expand Down
52 changes: 32 additions & 20 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,38 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
export interface NitricEvent<
T extends Record<string, any> = Record<string, any>
> {
/**
* Uniquely identifies the event.
*
* Within your app you must ensure the ID is unique.
* Subscribers can assume events with the same ID are duplicates and avoid reprocessing them
*/
id?: string;
/**
* An optional description of the event type.
*
* Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer.
*/
payloadType?: string;
/**
* The event's payload data, with details of the event.
*/
payload: T;
// export interface NitricEvent<
// T extends Record<string, any> = Record<string, any>
// > {
// /**
// * Uniquely identifies the event.
// *
// * Within your app you must ensure the ID is unique.
// * Subscribers can assume events with the same ID are duplicates and avoid reprocessing them
// */
// id?: string;
// /**
// * An optional description of the event type.
// *
// * Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer.
// */
// payloadType?: string;
// /**
// * The event's payload data, with details of the event.
// */
// payload: T;
// }

export class NitricEvent<T extends Record<string, any> = Record<string, any>> {
public readonly payload: T;
public readonly id?: string;
public readonly payloadType: string;

constructor(payload: T, id?: string, payloadType?: string) {
this.payload = payload;
this.id = id;
this.payloadType = payloadType || 'none';
}
}

export interface Task<T extends Record<string, any> = Record<string, any>> {
Expand Down

0 comments on commit 4ca1864

Please sign in to comment.