UNPKG

@aws-lambda-powertools/batch

Version:

The batch processing package for the Powertools for AWS Lambda (TypeScript) library.

119 lines (118 loc) 5.22 kB
import { EventType, SchemaVendor } from './constants.js'; import { ParsingError } from './errors.js'; /** * Extend the schema according to the event type passed. * * If `useTransformers` is true, extend using opinionated transformers. * Otherwise, extend without any transformers. * * The vendor is already checked at runtime to ensure Zod is being used when required using `StandardSchemaV1['~standard'].vendor`. * * @param options - The options for creating the extended schema * @param options.eventType - The type of event to process (SQS, Kinesis, DynamoDB) * @param options.innerSchema - The StandardSchema to be used for parsing. To avoid forcing a direct dependency on Zod, we use `unknown` here, which is not ideal but necessary. * @param options.useTransformers - Whether to use transformers for parsing * @param options.logger - A logger instance for logging */ const createExtendedSchema = async (options) => { const { eventType, innerSchema, transformer } = options; let schema = innerSchema; switch (transformer) { case 'json': { const { JSONStringified } = await import('@aws-lambda-powertools/parser/helpers'); // @ts-expect-error - we know it's a Zod schema due to the runtime check earlier schema = JSONStringified(innerSchema); break; } case 'base64': { const { Base64Encoded } = await import('@aws-lambda-powertools/parser/helpers'); // @ts-expect-error - we know it's a Zod schema due to the runtime check earlier schema = Base64Encoded(innerSchema); break; } case 'unmarshall': { const { DynamoDBMarshalled } = await import('@aws-lambda-powertools/parser/helpers/dynamodb'); // @ts-expect-error - we know it's a Zod schema due to the runtime check earlier schema = DynamoDBMarshalled(innerSchema); break; } } if (eventType === EventType.SQS) { const { SqsRecordSchema } = await import('@aws-lambda-powertools/parser/schemas/sqs'); return SqsRecordSchema.extend({ body: schema, }); } if (eventType === EventType.KinesisDataStreams) { const { KinesisDataStreamRecord, KinesisDataStreamRecordPayload } = await import('@aws-lambda-powertools/parser/schemas/kinesis'); return KinesisDataStreamRecord.extend({ kinesis: KinesisDataStreamRecordPayload.extend({ data: schema, }), }); } const { DynamoDBStreamRecord, DynamoDBStreamChangeRecordBase } = await import('@aws-lambda-powertools/parser/schemas/dynamodb'); return DynamoDBStreamRecord.extend({ dynamodb: DynamoDBStreamChangeRecordBase.extend({ OldImage: schema, NewImage: schema, }), }); }; /** * Parse the record with the passed schema and * return the result or throw the error depending on parsing success * * @param record - The record to be parsed * @param schema - The modified schema to parse with * @param logger - A logger instance for logging */ const parseWithErrorHandling = async (record, schema, logger) => { const { parse } = await import('@aws-lambda-powertools/parser'); const result = parse(record, undefined, schema, true); if (result.success) { return result.data; } const issues = result.error.cause; const errorMessage = issues .map((issue) => `${issue.path?.join('.')}: ${issue.message}`) .join('; '); logger.debug(`Failed to parse record: ${errorMessage}`); throw new ParsingError(errorMessage); }; /** * Parse the record according to the schema and event type passed. * * If the passed schema is already an extended schema, * use the schema directly to parse the record. * * Parts of the parser integration within BatchProcessor rely on Zod for schema transformations, * however some other parts also support other Standard Schema-compatible libraries. * * @param record - The record to be parsed * @param eventType - The type of event to process * @param logger - A logger instance for logging * @param parserConfig - The parser configuration options */ const parser = async (record, eventType, logger, parserConfig) => { const { schema, innerSchema, transformer } = parserConfig; // If the external schema is specified, use it to parse the record if (schema) { return parseWithErrorHandling(record, schema, logger); } if (innerSchema) { // Only proceed with schema extension if it's a Zod schema if (innerSchema['~standard'].vendor !== SchemaVendor.Zod) { logger.error('The schema provided is not supported. Only Zod schemas are supported for extension.'); throw new ParsingError('Unsupported schema type'); } return parseWithErrorHandling(record, await createExtendedSchema({ eventType, innerSchema, ...(transformer ? { transformer } : {}), }), logger); } logger.error('There was no schema or innerSchema provided'); throw new ParsingError('Either schema or innerSchema is required for parsing'); }; export { parser };