@aws-lambda-powertools/parser
Version:
The parser package for the Powertools for AWS Lambda (TypeScript) library.
100 lines (99 loc) • 3.63 kB
JavaScript
import { ZodError } from 'zod';
import { ParseError } from '../errors.js';
import { SqsSchema } from '../schemas/sqs.js';
import { envelopeDiscriminator } from './envelope.js';
/**
* SQS Envelope to extract array of Records
*
* The record's `body` parameter is a string and needs to be parsed against the provided schema.
*
* If you know that the `body` is a JSON string, you can use `JSONStringified` to parse it,
* for example:
*
* ```ts
* import { JSONStringified } from '@aws-lambda-powertools/helpers';
* import { SqsEnvelope } from '@aws-lambda-powertools/parser/envelopes/sqs';
*
* const schema = z.object({
* name: z.string(),
* });
*
* const parsed = SqsEnvelope.parse(event, JSONStringified(schema));
* ```
*/
const SqsEnvelope = {
/**
* This is a discriminator to differentiate whether an envelope returns an array or an object
* @hidden
*/
[envelopeDiscriminator]: 'array',
parse(data, schema) {
let parsedEnvelope;
try {
parsedEnvelope = SqsSchema.parse(data);
}
catch (error) {
throw new ParseError('Failed to parse SQS Envelope', {
cause: error,
});
}
return parsedEnvelope.Records.map((record, recordIndex) => {
let parsedRecord;
try {
parsedRecord = schema.parse(record.body);
}
catch (error) {
throw new ParseError(`Failed to parse SQS Record at index ${recordIndex}`, {
cause: new ZodError(error.issues.map((issue) => ({
...issue,
path: ['Records', recordIndex, 'body', ...issue.path],
}))),
});
}
return parsedRecord;
});
},
safeParse(data, schema) {
const parsedEnvelope = SqsSchema.safeParse(data);
if (!parsedEnvelope.success) {
return {
success: false,
error: new ParseError('Failed to parse SQS envelope', {
cause: parsedEnvelope.error,
}),
originalEvent: data,
};
}
const result = parsedEnvelope.data.Records.reduce((acc, record, index) => {
const parsedRecord = schema.safeParse(record.body);
if (!parsedRecord.success) {
const issues = parsedRecord.error.issues.map((issue) => ({
...issue,
path: ['Records', index, 'body', ...issue.path],
}));
acc.success = false;
// @ts-expect-error - index is assigned
acc.errors[index] = { issues };
return acc;
}
acc.records.push(parsedRecord.data);
return acc;
}, { success: true, records: [], errors: {} });
if (result.success) {
return { success: true, data: result.records };
}
const errorMessage = Object.keys(result.errors).length > 1
? `Failed to parse SQS Records at indexes ${Object.keys(result.errors).join(', ')}`
: `Failed to parse SQS Record at index ${Object.keys(result.errors)[0]}`;
return {
success: false,
error: new ParseError(errorMessage, {
cause: new ZodError(
// @ts-expect-error - issues are assigned because success is false
Object.values(result.errors).flatMap((error) => error.issues)),
}),
originalEvent: data,
};
},
};
export { SqsEnvelope };