From 5fea76a0c3be7bb9b0f26f1eb842a6a5b0759379 Mon Sep 17 00:00:00 2001 From: daschaa Date: Thu, 25 Jul 2024 20:07:33 +0200 Subject: [PATCH 1/2] chore(parser): exports Records schema --- packages/parser/package.json | 9 ++------ packages/parser/src/schemas/index.ts | 21 ++++++++++++++----- packages/parser/src/schemas/kafka.ts | 3 +++ .../parser/src/schemas/kinesis-firehose.ts | 13 +++++++++++- packages/parser/src/schemas/ses.ts | 5 ++++- packages/parser/src/schemas/sns.ts | 13 +++++++++++- packages/parser/src/schemas/sqs.ts | 3 +++ 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/parser/package.json b/packages/parser/package.json index 26521bf83a..5a1d3c52de 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -62,10 +62,7 @@ }, "typesVersions": { "*": { - "types": [ - "./lib/cjs/types/index.d.ts", - "./lib/esm/types/index.d.ts" - ], + "types": ["./lib/cjs/types/index.d.ts", "./lib/esm/types/index.d.ts"], "middleware": [ "./lib/cjs/middleware/parser.d.ts", "./lib/esm/middleware/parser.d.ts" @@ -90,9 +87,7 @@ }, "main": "./lib/cjs/index.js", "types": "./lib/cjs/index.d.ts", - "files": [ - "lib" - ], + "files": ["lib"], "repository": { "type": "git", "url": "git+https://github.com/aws-powertools/powertools-lambda-typescript.git" diff --git a/packages/parser/src/schemas/index.ts b/packages/parser/src/schemas/index.ts index e4044d8e9d..ae78f39f12 100644 --- a/packages/parser/src/schemas/index.ts +++ b/packages/parser/src/schemas/index.ts @@ -20,11 +20,17 @@ export { } from './cloudwatch.js'; export { DynamoDBStreamSchema } from './dynamodb.js'; export { EventBridgeSchema } from './eventbridge.js'; -export { KafkaMskEventSchema, KafkaSelfManagedEventSchema } from './kafka.js'; -export { KinesisDataStreamSchema } from './kinesis.js'; +export { + KafkaMskEventSchema, + KafkaSelfManagedEventSchema, + KafkaRecordSchema, +} from './kafka.js'; +export { KinesisDataStreamSchema, KinesisDataStreamRecord } from './kinesis.js'; export { KinesisFirehoseSchema, KinesisFirehoseSqsSchema, + KinesisFirehoseRecord, + KinesisFirehoseSqsRecord, } from './kinesis-firehose.js'; export { LambdaFunctionUrlSchema } from './lambda.js'; export { @@ -33,8 +39,13 @@ export { S3ObjectLambdaEventSchema, S3Schema, } from './s3.js'; -export { SesSchema } from './ses.js'; -export { SnsSchema } from './sns.js'; -export { SqsSchema } from './sqs.js'; +export { SesSchema, SesRecordSchema } from './ses.js'; +export { + SnsSchema, + SnsRecordSchema, + SnsSqsNotificationSchema, + SnsNotificationSchema, +} from './sns.js'; +export { SqsSchema, SqsRecordSchema } from './sqs.js'; export { VpcLatticeSchema } from './vpc-lattice.js'; export { VpcLatticeV2Schema } from './vpc-latticev2.js'; diff --git a/packages/parser/src/schemas/kafka.ts b/packages/parser/src/schemas/kafka.ts index 067346f123..89a9b7e56a 100644 --- a/packages/parser/src/schemas/kafka.ts +++ b/packages/parser/src/schemas/kafka.ts @@ -1,5 +1,8 @@ import { z } from 'zod'; +/** + * Zod schema for a Kafka record from an Kafka event. + */ const KafkaRecordSchema = z.object({ topic: z.string(), partition: z.number(), diff --git a/packages/parser/src/schemas/kinesis-firehose.ts b/packages/parser/src/schemas/kinesis-firehose.ts index 57d7d5a2ae..03a34fbab4 100644 --- a/packages/parser/src/schemas/kinesis-firehose.ts +++ b/packages/parser/src/schemas/kinesis-firehose.ts @@ -22,12 +22,18 @@ const KinesisFireHoseBaseSchema = z.object({ sourceKinesisStreamArn: z.string().optional(), }); +/** + * Zod schema for a Kinesis Firehose record from an Kinesis Firehose event. + */ const KinesisFirehoseRecord = KinesisFireHoseRecordBase.extend({ data: z .string() .transform((data) => Buffer.from(data, 'base64').toString('utf8')), }); +/** + * Zod schema for a SQS record from an Kinesis Firehose event. + */ const KinesisFirehoseSqsRecord = KinesisFireHoseRecordBase.extend({ data: z.string().transform((data) => { try { @@ -111,4 +117,9 @@ const KinesisFirehoseSqsSchema = KinesisFireHoseBaseSchema.extend({ records: z.array(KinesisFirehoseSqsRecord), }); -export { KinesisFirehoseSchema, KinesisFirehoseSqsSchema }; +export { + KinesisFirehoseSchema, + KinesisFirehoseSqsSchema, + KinesisFirehoseRecord, + KinesisFirehoseSqsRecord, +}; diff --git a/packages/parser/src/schemas/ses.ts b/packages/parser/src/schemas/ses.ts index c065f2e639..0ed9866cc9 100644 --- a/packages/parser/src/schemas/ses.ts +++ b/packages/parser/src/schemas/ses.ts @@ -52,6 +52,9 @@ const SesMessage = z.object({ receipt: SesReceipt, }); +/** + * Zod schema for a SES record from an SES event. + */ const SesRecordSchema = z.object({ eventSource: z.literal('aws:ses'), eventVersion: z.string(), @@ -173,4 +176,4 @@ const SesSchema = z.object({ Records: z.array(SesRecordSchema), }); -export { SesSchema }; +export { SesSchema, SesRecordSchema }; diff --git a/packages/parser/src/schemas/sns.ts b/packages/parser/src/schemas/sns.ts index 1e90a4b265..2dd3688208 100644 --- a/packages/parser/src/schemas/sns.ts +++ b/packages/parser/src/schemas/sns.ts @@ -5,6 +5,9 @@ const SnsMsgAttribute = z.object({ Value: z.string(), }); +/** + * Zod schema for a SNS event notification record. + */ const SnsNotificationSchema = z.object({ Subject: z.string().optional(), TopicArn: z.string(), @@ -58,6 +61,9 @@ const SnsSqsNotificationSchema = SnsNotificationSchema.extend({ SigningCertUrl: true, }); +/** + * Zod schema for a SNS record inside of an SNS event. + */ const SnsRecordSchema = z.object({ EventSource: z.literal('aws:sns'), EventVersion: z.string(), @@ -110,4 +116,9 @@ const SnsSchema = z.object({ Records: z.array(SnsRecordSchema), }); -export { SnsSchema, SnsSqsNotificationSchema }; +export { + SnsSchema, + SnsSqsNotificationSchema, + SnsRecordSchema, + SnsNotificationSchema, +}; diff --git a/packages/parser/src/schemas/sqs.ts b/packages/parser/src/schemas/sqs.ts index c861a94dd3..42aa348d30 100644 --- a/packages/parser/src/schemas/sqs.ts +++ b/packages/parser/src/schemas/sqs.ts @@ -23,6 +23,9 @@ const SqsAttributesSchema = z.object({ DeadLetterQueueSourceArn: z.string().optional(), }); +/** + * Zod schema for a SQS record inside an SQS event. + */ const SqsRecordSchema = z.object({ messageId: z.string(), receiptHandle: z.string(), From 4ab69d78883a77ca0fd20e76eabe4f889540c77b Mon Sep 17 00:00:00 2001 From: daschaa Date: Thu, 25 Jul 2024 22:03:45 +0200 Subject: [PATCH 2/2] chore(parser): add tests for newly introduced schemas --- packages/parser/src/schemas/index.ts | 4 +- .../parser/src/schemas/kinesis-firehose.ts | 12 +++--- packages/parser/src/types/schema.ts | 32 +++++++++++++++ .../parser/tests/unit/schema/kafka.test.ts | 11 +++++ .../parser/tests/unit/schema/kinesis.test.ts | 41 +++++++++++++++++++ packages/parser/tests/unit/schema/ses.test.ts | 15 +++++-- packages/parser/tests/unit/schema/sns.test.ts | 39 ++++++++++++++++-- packages/parser/tests/unit/schema/sqs.test.ts | 11 ++++- 8 files changed, 149 insertions(+), 16 deletions(-) diff --git a/packages/parser/src/schemas/index.ts b/packages/parser/src/schemas/index.ts index ae78f39f12..6a087bf9e6 100644 --- a/packages/parser/src/schemas/index.ts +++ b/packages/parser/src/schemas/index.ts @@ -29,8 +29,8 @@ export { KinesisDataStreamSchema, KinesisDataStreamRecord } from './kinesis.js'; export { KinesisFirehoseSchema, KinesisFirehoseSqsSchema, - KinesisFirehoseRecord, - KinesisFirehoseSqsRecord, + KinesisFirehoseRecordSchema, + KinesisFirehoseSqsRecordSchema, } from './kinesis-firehose.js'; export { LambdaFunctionUrlSchema } from './lambda.js'; export { diff --git a/packages/parser/src/schemas/kinesis-firehose.ts b/packages/parser/src/schemas/kinesis-firehose.ts index 03a34fbab4..a9831acfe3 100644 --- a/packages/parser/src/schemas/kinesis-firehose.ts +++ b/packages/parser/src/schemas/kinesis-firehose.ts @@ -25,7 +25,7 @@ const KinesisFireHoseBaseSchema = z.object({ /** * Zod schema for a Kinesis Firehose record from an Kinesis Firehose event. */ -const KinesisFirehoseRecord = KinesisFireHoseRecordBase.extend({ +const KinesisFirehoseRecordSchema = KinesisFireHoseRecordBase.extend({ data: z .string() .transform((data) => Buffer.from(data, 'base64').toString('utf8')), @@ -34,7 +34,7 @@ const KinesisFirehoseRecord = KinesisFireHoseRecordBase.extend({ /** * Zod schema for a SQS record from an Kinesis Firehose event. */ -const KinesisFirehoseSqsRecord = KinesisFireHoseRecordBase.extend({ +const KinesisFirehoseSqsRecordSchema = KinesisFireHoseRecordBase.extend({ data: z.string().transform((data) => { try { return SqsRecordSchema.parse( @@ -89,7 +89,7 @@ const KinesisFirehoseSqsRecord = KinesisFireHoseRecordBase.extend({ * @see {@link https://docs.aws.amazon.com/lambda/latest/dg/services-kinesisfirehose.html} */ const KinesisFirehoseSchema = KinesisFireHoseBaseSchema.extend({ - records: z.array(KinesisFirehoseRecord), + records: z.array(KinesisFirehoseRecordSchema), }); /** @@ -114,12 +114,12 @@ const KinesisFirehoseSchema = KinesisFireHoseBaseSchema.extend({ * @see {@link types.KinesisFireHoseSqsEvent | KinesisFireHoseSqsEvent} */ const KinesisFirehoseSqsSchema = KinesisFireHoseBaseSchema.extend({ - records: z.array(KinesisFirehoseSqsRecord), + records: z.array(KinesisFirehoseSqsRecordSchema), }); export { KinesisFirehoseSchema, KinesisFirehoseSqsSchema, - KinesisFirehoseRecord, - KinesisFirehoseSqsRecord, + KinesisFirehoseRecordSchema, + KinesisFirehoseSqsRecordSchema, }; diff --git a/packages/parser/src/types/schema.ts b/packages/parser/src/types/schema.ts index 4d658c8513..fc3b8c2614 100644 --- a/packages/parser/src/types/schema.ts +++ b/packages/parser/src/types/schema.ts @@ -11,17 +11,25 @@ import type { DynamoDBStreamSchema, EventBridgeSchema, KafkaMskEventSchema, + KafkaRecordSchema, KafkaSelfManagedEventSchema, KinesisDataStreamSchema, + KinesisFirehoseRecordSchema, KinesisFirehoseSchema, + KinesisFirehoseSqsRecordSchema, KinesisFirehoseSqsSchema, LambdaFunctionUrlSchema, S3EventNotificationEventBridgeSchema, S3ObjectLambdaEventSchema, S3Schema, S3SqsEventNotificationSchema, + SesRecordSchema, SesSchema, + SnsNotificationSchema, + SnsRecordSchema, SnsSchema, + SnsSqsNotificationSchema, + SqsRecordSchema, SqsSchema, VpcLatticeSchema, VpcLatticeV2Schema, @@ -55,14 +63,20 @@ type EventBridgeEvent = z.infer; type KafkaSelfManagedEvent = z.infer; +type KafkaRecord = z.infer; + type KafkaMskEvent = z.infer; type KinesisDataStreamEvent = z.infer; type KinesisFireHoseEvent = z.infer; +type KinesisFirehoseRecord = z.infer; + type KinesisFireHoseSqsEvent = z.infer; +type KinesisFirehoseSqsRecord = z.infer; + type LambdaFunctionUrlEvent = z.infer; type S3Event = z.infer; @@ -77,10 +91,20 @@ type S3ObjectLambdaEvent = z.infer; type SesEvent = z.infer; +type SesRecord = z.infer; + type SnsEvent = z.infer; +type SnsSqsNotification = z.infer; + +type SnsNotification = z.infer; + +type SnsRecord = z.infer; + type SqsEvent = z.infer; +type SqsRecord = z.infer; + type VpcLatticeEvent = z.infer; type VpcLatticeEventV2 = z.infer; @@ -98,17 +122,25 @@ export type { EventBridgeEvent, KafkaSelfManagedEvent, KafkaMskEvent, + KafkaRecord, KinesisDataStreamEvent, KinesisFireHoseEvent, + KinesisFirehoseRecord, KinesisFireHoseSqsEvent, + KinesisFirehoseSqsRecord, LambdaFunctionUrlEvent, S3Event, S3EventNotificationEventBridge, S3SqsEventNotification, S3ObjectLambdaEvent, SesEvent, + SesRecord, SnsEvent, + SnsSqsNotification, + SnsNotification, + SnsRecord, SqsEvent, + SqsRecord, VpcLatticeEvent, VpcLatticeEventV2, }; diff --git a/packages/parser/tests/unit/schema/kafka.test.ts b/packages/parser/tests/unit/schema/kafka.test.ts index c6aab47348..6292f3001f 100644 --- a/packages/parser/tests/unit/schema/kafka.test.ts +++ b/packages/parser/tests/unit/schema/kafka.test.ts @@ -6,8 +6,11 @@ import { KafkaMskEventSchema, + KafkaRecordSchema, KafkaSelfManagedEventSchema, } from '../../../src/schemas/'; +import type { KafkaSelfManagedEvent } from '../../../src/types'; +import type { KafkaRecord } from '../../../src/types/schema'; import { TestEvents } from './utils.js'; describe('Kafka ', () => { @@ -60,4 +63,12 @@ describe('Kafka ', () => { expect(parsed.bootstrapServers).toBeUndefined(); }); + it('should parse kafka record from kafka event', () => { + const kafkaEventMsk: KafkaSelfManagedEvent = + TestEvents.kafkaEventSelfManaged as KafkaSelfManagedEvent; + const parsedRecord: KafkaRecord = KafkaRecordSchema.parse( + kafkaEventMsk.records['mytopic-0'][0] + ); + expect(parsedRecord.topic).toEqual('mytopic'); + }); }); diff --git a/packages/parser/tests/unit/schema/kinesis.test.ts b/packages/parser/tests/unit/schema/kinesis.test.ts index 31c4400757..e107d1ae2f 100644 --- a/packages/parser/tests/unit/schema/kinesis.test.ts +++ b/packages/parser/tests/unit/schema/kinesis.test.ts @@ -5,10 +5,22 @@ */ import { + KinesisDataStreamRecord, KinesisDataStreamSchema, + KinesisFirehoseRecordSchema, KinesisFirehoseSchema, + KinesisFirehoseSqsRecordSchema, KinesisFirehoseSqsSchema, } from '../../../src/schemas/'; +import type { + KinesisDataStreamEvent, + KinesisFireHoseEvent, + KinesisFireHoseSqsEvent, +} from '../../../src/types'; +import type { + KinesisFirehoseRecord, + KinesisFirehoseSqsRecord, +} from '../../../src/types/schema'; import { TestEvents } from './utils.js'; describe('Kinesis ', () => { @@ -69,4 +81,33 @@ describe('Kinesis ', () => { const parsed = KinesisFirehoseSqsSchema.parse(kinesisFirehoseSQSEvent); expect(parsed.records[0].data).toEqual('not a valid json'); }); + it('should parse a kinesis record from a kinesis event', () => { + const kinesisStreamEvent: KinesisDataStreamEvent = + TestEvents.kinesisStreamEvent as KinesisDataStreamEvent; + const parsedRecord = KinesisDataStreamRecord.parse( + kinesisStreamEvent.Records[0] + ); + + expect(parsedRecord.eventName).toEqual('aws:kinesis:record'); + }); + + it('should parse a kinesis firehose record from a kinesis firehose event', () => { + const kinesisFirehoseEvent: KinesisFireHoseEvent = + TestEvents.kinesisFirehoseKinesisEvent as KinesisFireHoseEvent; + const parsedRecord: KinesisFirehoseRecord = + KinesisFirehoseRecordSchema.parse(kinesisFirehoseEvent.records[0]); + + expect(parsedRecord.data).toEqual('Hello World'); + }); + + it('should parse a sqs record from a kinesis firehose event', () => { + const kinesisFireHoseSqsEvent: KinesisFireHoseSqsEvent = + TestEvents.kinesisFirehoseSQSEvent as KinesisFireHoseSqsEvent; + const parsed: KinesisFirehoseSqsRecord = + KinesisFirehoseSqsRecordSchema.parse(kinesisFireHoseSqsEvent.records[0]); + + expect(parsed.recordId).toEqual( + '49640912821178817833517986466168945147170627572855734274000000' + ); + }); }); diff --git a/packages/parser/tests/unit/schema/ses.test.ts b/packages/parser/tests/unit/schema/ses.test.ts index 010fa4872c..7c27a83d97 100644 --- a/packages/parser/tests/unit/schema/ses.test.ts +++ b/packages/parser/tests/unit/schema/ses.test.ts @@ -4,12 +4,21 @@ * @group unit/parser/schema/ */ -import { SesSchema } from '../../../src/schemas/'; +import { SesRecordSchema, SesSchema } from '../../../src/schemas/'; +import type { SesEvent } from '../../../src/types'; +import type { SesRecord } from '../../../src/types/schema'; import { TestEvents } from './utils.js'; -describe('Schema:', () => { - it('SES should parse ses event', () => { +describe('SES', () => { + it('should parse ses event', () => { const sesEvent = TestEvents.sesEvent; expect(SesSchema.parse(sesEvent)).toEqual(sesEvent); }); + + it('should parse record from ses event', () => { + const sesEvent: SesEvent = TestEvents.sesEvent as SesEvent; + const parsed: SesRecord = SesRecordSchema.parse(sesEvent.Records[0]); + + expect(parsed.ses.mail.source).toEqual('janedoe@example.com'); + }); }); diff --git a/packages/parser/tests/unit/schema/sns.test.ts b/packages/parser/tests/unit/schema/sns.test.ts index 26a212b7ad..7ddb7f1132 100644 --- a/packages/parser/tests/unit/schema/sns.test.ts +++ b/packages/parser/tests/unit/schema/sns.test.ts @@ -4,12 +4,45 @@ * @group unit/parser/schema/ */ -import { SnsSchema } from '../../../src/schemas/'; +import { + SnsNotificationSchema, + SnsRecordSchema, + SnsSchema, + SnsSqsNotificationSchema, +} from '../../../src/schemas/'; +import type { SnsEvent, SqsEvent } from '../../../src/types'; +import type { + SnsNotification, + SnsRecord, + SnsSqsNotification, +} from '../../../src/types/schema'; import { TestEvents } from './utils.js'; -describe('Schema:', () => { - it('SNS should parse sns event', () => { +describe('SNS', () => { + it('should parse sns event', () => { const snsEvent = TestEvents.snsEvent; expect(SnsSchema.parse(snsEvent)).toEqual(snsEvent); }); + it('should parse record from sns event', () => { + const snsEvent: SnsEvent = TestEvents.snsEvent as SnsEvent; + const parsed: SnsRecord = SnsRecordSchema.parse(snsEvent.Records[0]); + expect(parsed.Sns.Message).toEqual('Hello from SNS!'); + }); + it('should parse sns notification from sns event', () => { + const snsEvent: SnsEvent = TestEvents.snsEvent as SnsEvent; + const parsed: SnsNotification = SnsNotificationSchema.parse( + snsEvent.Records[0].Sns + ); + expect(parsed.Message).toEqual('Hello from SNS!'); + }); + it('should parse sns notification from sqs -> sns event', () => { + const sqsEvent: SqsEvent = TestEvents.snsSqsEvent as SqsEvent; + console.log(sqsEvent.Records[0].body); + const parsed: SnsSqsNotification = SnsSqsNotificationSchema.parse( + JSON.parse(sqsEvent.Records[0].body) + ); + expect(parsed.TopicArn).toEqual( + 'arn:aws:sns:eu-west-1:231436140809:powertools265' + ); + }); }); diff --git a/packages/parser/tests/unit/schema/sqs.test.ts b/packages/parser/tests/unit/schema/sqs.test.ts index d92f0d73e5..9514338395 100644 --- a/packages/parser/tests/unit/schema/sqs.test.ts +++ b/packages/parser/tests/unit/schema/sqs.test.ts @@ -4,12 +4,19 @@ * @group unit/parser/schema/ */ -import { SqsSchema } from '../../../src/schemas/'; +import { SqsRecordSchema, SqsSchema } from '../../../src/schemas/'; +import type { SqsEvent } from '../../../src/types'; +import type { SqsRecord } from '../../../src/types/schema'; import { TestEvents } from './utils.js'; -describe('SQS ', () => { +describe('SQS', () => { it('should parse sqs event', () => { const sqsEvent = TestEvents.sqsEvent; expect(SqsSchema.parse(sqsEvent)).toEqual(sqsEvent); }); + it('should parse record from sqs event', () => { + const sqsEvent: SqsEvent = TestEvents.sqsEvent as SqsEvent; + const parsed: SqsRecord = SqsRecordSchema.parse(sqsEvent.Records[0]); + expect(parsed.body).toEqual('Test message.'); + }); });