aws-powertools/powertools-lambda-typescript

Bug: SnsSqsEnvelope does not parse `Message` as JSON

Closed this issue · 4 comments

Expected Behavior

Using SnsSqsEnvelope should parse a JSON body in the Message field.

Current Behavior

Currently, the parser will crash out with the following error:

ParseError: Failed to parse SQS Record at index 0

Code snippet

import { SnsSqsEnvelope } from '@aws-lambda-powertools/parser/envelopes/sns-sqs';
import { z } from 'zod';

const person = z.object({
    firstName: z.string(),
    lastName: z.string(),
});

const sqsRecord = {
    messageId: '059f36b4-87a3-44ab-83d2-661975830a7d',
    receiptHandle: 'AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...',
    attributes: {
        ApproximateReceiveCount: '1',
        SentTimestamp: '1545082649183',
        SenderId: 'AIDAIENQZJOLO23YVJ4VO',
        ApproximateFirstReceiveTimestamp: '1545082649185',
    },
    messageAttributes: {},
    md5OfBody: 'e4e68fb7bd0e697a0ae8f1bb342846b3',
    eventSource: 'aws:sqs',
    eventSourceARN: 'arn:aws:sqs:eu-west-1:123456789012:my-queue',
    awsRegion: 'eu-west-1',
    body: JSON.stringify({
        SignatureVersion: '1',
        Timestamp: new Date().toISOString(),
        Signature: 'EXAMPLEw6JR0u+X6pYkZf+QTTJvtuY=',
        SigningCertUrl: 'https://sns.eu-west-1.amazonaws.com/SimpleNotificationService.pem',
        MessageId: '95df01b4-ee98-5cb9-9903-4c221d41eb5e',
        Message: JSON.stringify({
            firstName: 'Bob',
            lastName: 'Smith'
        }),
        MessageAttributes: {
            Attribute1: {
                Type: 'String',
                Value: 'Value1',
            },
        },
        UnsubscribeUrl: 'https://sns.eu-west-1.amazonaws.com/?Action=Unsubscribe',
        TopicArn: 'arn:aws:sns:eu-west-1:123456789012:ExampleTopic',
        Type: 'Notification',
    }),
};

const sqsEvent = { Records: [sqsRecord] };

const people = SnsSqsEnvelope.parse(sqsEvent, person);

for (const person of people) {
    console.log(`${person.firstName} ${person.lastName}`);
}

Steps to Reproduce

mkdir repro
cd repro
npm init --yes
npm i @aws-lambda-powertools/parser zod
# paste snippet code into index.js
node index.js

Possible Solution

Update this code:

return schema.parse(
SnsSqsNotificationSchema.parse(JSON.parse(record.body)).Message
);

To:

 return schema.parse( 
   JSON.parse(SnsSqsNotificationSchema.parse(JSON.parse(record.body)).Message)
 );

Powertools for AWS Lambda (TypeScript) version

latest

AWS Lambda function runtime

22.x

Packaging format used

npm

Execution logs

Hi @ben-eb, thanks for opening this issue.

The envelope intentionally doesn't force JSON parsing because, in practice, SQS messages don't have to be JSON stringified objects but can also be plain text strings or strings with other types of encodings.

Because of this, when passing the schema for your payload, if you know that it's going to be JSON encoded you should use the JSONStringified helper which tells Zod to run JSON.parse before parsing.

Your example should add these lines:

import { JSONStringified } from '@aws-lambda-powertools/parser/helpers';
const people = SnsSqsEnvelope.parse(sqsEvent, JSONStringified(person));

Many thanks, missed this in the docs. 👍

Warning

This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Warning

This issue is now closed. Please be mindful that future comments are hard for our team to see.
If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.