From 16f944c994fa3d51fc5d40b354cebf7c59e5b363 Mon Sep 17 00:00:00 2001 From: Daniel Abib Date: Sat, 30 Aug 2025 09:03:52 -0300 Subject: [PATCH 1/3] refactor(parser): Improve SQS models with examples and descriptions Enhances the SQS parser models with field descriptions and examples using Pydantic's Field() functionality. This improvement provides better documentation and metadata for SQS event parsing, following the pattern established in PR #7100. All field descriptions are based on official AWS SQS documentation and include realistic examples from actual test events. Closes #7116 --- .../utilities/parser/models/sqs.py | 163 +++++++++++++++--- 1 file changed, 137 insertions(+), 26 deletions(-) diff --git a/aws_lambda_powertools/utilities/parser/models/sqs.py b/aws_lambda_powertools/utilities/parser/models/sqs.py index efa5130bf06..23af87e9578 100644 --- a/aws_lambda_powertools/utilities/parser/models/sqs.py +++ b/aws_lambda_powertools/utilities/parser/models/sqs.py @@ -1,27 +1,78 @@ from datetime import datetime from typing import Dict, List, Literal, Optional, Sequence, Type, Union -from pydantic import BaseModel +from pydantic import BaseModel, Field class SqsAttributesModel(BaseModel): - ApproximateReceiveCount: str - ApproximateFirstReceiveTimestamp: datetime - MessageDeduplicationId: Optional[str] = None - MessageGroupId: Optional[str] = None - SenderId: str - SentTimestamp: datetime - SequenceNumber: Optional[str] = None - AWSTraceHeader: Optional[str] = None - DeadLetterQueueSourceArn: Optional[str] = None + ApproximateReceiveCount: str = Field( + description="The number of times a message has been received across all queues but not deleted.", + examples=["1", "2"], + ) + ApproximateFirstReceiveTimestamp: datetime = Field( + description="The time the message was first received from the queue (epoch time in milliseconds).", + examples=["1545082649185", "1545082650649", "1713185156612"], + ) + MessageDeduplicationId: Optional[str] = Field( + default=None, + description="Returns the value provided by the producer that calls the SendMessage action.", + examples=["msg-dedup-12345", "unique-msg-abc123", None], + ) + MessageGroupId: Optional[str] = Field( + default=None, + description="Returns the value provided by the producer that calls the SendMessage action.", + examples=["order-processing", "user-123-updates", None], + ) + SenderId: str = Field( + description="The user ID for IAM users or the role ID for IAM roles that sent the message.", + examples=["AIDAIENQZJOLO23YVJ4VO", "AMCXIENQZJOLO23YVJ4VO"], + ) + SentTimestamp: datetime = Field( + description="The time the message was sent to the queue (epoch time in milliseconds).", + examples=["1545082649183", "1545082650636", "1713185156609"], + ) + SequenceNumber: Optional[str] = Field( + default=None, + description="Returns the value provided by Amazon SQS.", + examples=["18849496460467696128", "18849496460467696129", None], + ) + AWSTraceHeader: Optional[str] = Field( + default=None, + description="The AWS X-Ray trace header for request tracing.", + examples=["Root=1-5e1b4151-5ac6c58239c1e5b4", None], + ) + DeadLetterQueueSourceArn: Optional[str] = Field( + default=None, + description="The ARN of the dead-letter queue from which the message was moved.", + examples=["arn:aws:sqs:eu-central-1:123456789012:sqs-redrive-SampleQueue-RNvLCpwGmLi7", None], + ) class SqsMsgAttributeModel(BaseModel): - stringValue: Optional[str] = None - binaryValue: Optional[str] = None - stringListValues: List[str] = [] - binaryListValues: List[str] = [] - dataType: str + stringValue: Optional[str] = Field( + default=None, + description="The string value of the message attribute.", + examples=["100", "active", "user-12345", None], + ) + binaryValue: Optional[str] = Field( + default=None, + description="The binary value of the message attribute, base64-encoded.", + examples=["base64Str", "SGVsbG8gV29ybGQ=", None], + ) + stringListValues: List[str] = Field( + default=[], + description="A list of string values for the message attribute.", + examples=[["item1", "item2"], ["tag1", "tag2", "tag3"], []], + ) + binaryListValues: List[str] = Field( + default=[], + description="A list of binary values for the message attribute, each base64-encoded.", + examples=[["dmFsdWUx", "dmFsdWUy"], ["aGVsbG8="], []], + ) + dataType: str = Field( + description="The data type of the message attribute (String, Number, Binary, or custom data type).", + examples=["String", "Number", "Binary", "String.custom", "Number.float"], + ) # context on why it's commented: https://github.com/aws-powertools/powertools-lambda-python/pull/118 # Amazon SQS supports the logical data types String, Number, and Binary with optional custom data type @@ -49,17 +100,77 @@ class SqsMsgAttributeModel(BaseModel): class SqsRecordModel(BaseModel): - messageId: str - receiptHandle: str - body: Union[str, Type[BaseModel], BaseModel] - attributes: SqsAttributesModel - messageAttributes: Dict[str, SqsMsgAttributeModel] - md5OfBody: str - md5OfMessageAttributes: Optional[str] = None - eventSource: Literal["aws:sqs"] - eventSourceARN: str - awsRegion: str + messageId: str = Field( + description="A unique identifier for the message. A MessageId is considered unique across all AWS accounts for an extended period of time.", + examples=[ + "059f36b4-87a3-44ab-83d2-661975830a7d", + "2e1424d4-f796-459a-8184-9c92662be6da", + "db37cc61-1bb0-4e77-b6f3-7cf87f44a72a", + ], + ) + receiptHandle: str = Field( + description="An identifier associated with the act of receiving the message, used for message deletion.", + examples=[ + "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...", + "AQEBl1pqxv+ZHkarVAWZUyWgj2mmqJGLBTo6YFOi/bw1QpBTpJBGJPLOTZrjKztKIbAB8EXkG7zHlbkn+Ze/AHMKKuhST9azHu8LyF4Ffu9uPkZc5xzggXlfFBWH3TUKyV+F5Obaj3esyX8YfM/zfgjbRuu5nc2tfPhvaSYEaTZsdMpzIB5tyKvHxAltLxK7upRHeoT768M9UrFYswarFTBn8piDbnsPsUhi8Q9G4Q4xSI0fLQANmryBsRJIzGQTVxenDad+MJ7XEL+hD3p2DmW+ycvv6WD7bdedqQuroQG8+ca1Dz7s3CBbXw9ZZnUziPa7LH1j1Lky5bAxpNF+BlurRS9pFBnomhwpylrGxtGfaEmUW1G7jnrG97sZNOLOFUykbQgroZPXmjzMBdvtgq9ZmQfCch3LOXN267+PKc56VR4=", + ], + ) + body: Union[str, Type[BaseModel], BaseModel] = Field( + description="The message's contents (not URL-encoded). Can be plain text or JSON.", + examples=[ + "Test message.", + '{"message": "foo1"}', + "hello world", + ], + ) + attributes: SqsAttributesModel = Field( + description="A map of the attributes requested in ReceiveMessage to their respective values.", + ) + messageAttributes: Dict[str, SqsMsgAttributeModel] = Field( + description="User-defined message attributes as key-value pairs.", + examples=[ + {"testAttr": {"stringValue": "100", "binaryValue": "base64Str", "dataType": "Number"}}, + {}, + ], + ) + md5OfBody: str = Field( + description="An MD5 digest of the non-URL-encoded message body string.", + examples=[ + "e4e68fb7bd0e697a0ae8f1bb342846b3", + "6a204bd89f3c8348afd5c77c717a097a", + ], + ) + md5OfMessageAttributes: Optional[str] = Field( + default=None, + description="An MD5 digest of the non-URL-encoded message attribute string. You can use this attribute to verify that Amazon SQS received the message correctly.", + examples=[ + "00484c68...59e48fb7", + "b25f48e8...f4e4f0bb", + None, + ], + ) + eventSource: Literal["aws:sqs"] = Field( + description="The AWS service that invoked the function.", + examples=["aws:sqs"], + ) + eventSourceARN: str = Field( + description="The Amazon Resource Name (ARN) of the SQS queue.", + examples=[ + "arn:aws:sqs:us-east-2:123456789012:my-queue", + "arn:aws:sqs:eu-central-1:123456789012:sqs-redrive-SampleDLQ-Emgp9MFSLBZm", + ], + ) + awsRegion: str = Field( + description="The AWS region where the SQS queue is located.", + examples=["us-east-1", "us-east-2", "eu-central-1"], + ) class SqsModel(BaseModel): - Records: Sequence[SqsRecordModel] + Records: Sequence[SqsRecordModel] = Field( + description="A list of SQS message records included in the event.", + examples=[ + [{"messageId": "059f36b4-87a3-44ab-83d2-661975830a7d", "body": "Test message."}] + ], + ) From 25b1bfeceafa37196265cfab19b9a4e768601b5b Mon Sep 17 00:00:00 2001 From: Daniel Abib Date: Mon, 1 Sep 2025 08:06:24 -0300 Subject: [PATCH 2/3] style: remove long receiptHandle example and apply formatting Remove extremely long receiptHandle example as requested by leandrodamascena and apply ruff formatting to fix CI issues. --- aws_lambda_powertools/utilities/parser/models/sqs.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/aws_lambda_powertools/utilities/parser/models/sqs.py b/aws_lambda_powertools/utilities/parser/models/sqs.py index 23af87e9578..85db1a1a4cb 100644 --- a/aws_lambda_powertools/utilities/parser/models/sqs.py +++ b/aws_lambda_powertools/utilities/parser/models/sqs.py @@ -113,7 +113,6 @@ class SqsRecordModel(BaseModel): examples=[ "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", "AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...", - "AQEBl1pqxv+ZHkarVAWZUyWgj2mmqJGLBTo6YFOi/bw1QpBTpJBGJPLOTZrjKztKIbAB8EXkG7zHlbkn+Ze/AHMKKuhST9azHu8LyF4Ffu9uPkZc5xzggXlfFBWH3TUKyV+F5Obaj3esyX8YfM/zfgjbRuu5nc2tfPhvaSYEaTZsdMpzIB5tyKvHxAltLxK7upRHeoT768M9UrFYswarFTBn8piDbnsPsUhi8Q9G4Q4xSI0fLQANmryBsRJIzGQTVxenDad+MJ7XEL+hD3p2DmW+ycvv6WD7bdedqQuroQG8+ca1Dz7s3CBbXw9ZZnUziPa7LH1j1Lky5bAxpNF+BlurRS9pFBnomhwpylrGxtGfaEmUW1G7jnrG97sZNOLOFUykbQgroZPXmjzMBdvtgq9ZmQfCch3LOXN267+PKc56VR4=", ], ) body: Union[str, Type[BaseModel], BaseModel] = Field( @@ -170,7 +169,5 @@ class SqsRecordModel(BaseModel): class SqsModel(BaseModel): Records: Sequence[SqsRecordModel] = Field( description="A list of SQS message records included in the event.", - examples=[ - [{"messageId": "059f36b4-87a3-44ab-83d2-661975830a7d", "body": "Test message."}] - ], + examples=[[{"messageId": "059f36b4-87a3-44ab-83d2-661975830a7d", "body": "Test message."}]], ) From a1d1b82d1da70c2864e0b69b70474b43bdaa9986 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 1 Sep 2025 12:52:47 +0100 Subject: [PATCH 3/3] Fix styles --- aws_lambda_powertools/utilities/parser/models/sqs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/utilities/parser/models/sqs.py b/aws_lambda_powertools/utilities/parser/models/sqs.py index 85db1a1a4cb..06452cd2a8f 100644 --- a/aws_lambda_powertools/utilities/parser/models/sqs.py +++ b/aws_lambda_powertools/utilities/parser/models/sqs.py @@ -101,7 +101,7 @@ class SqsMsgAttributeModel(BaseModel): class SqsRecordModel(BaseModel): messageId: str = Field( - description="A unique identifier for the message. A MessageId is considered unique across all AWS accounts for an extended period of time.", + description="A unique identifier for the message. A MessageId is considered unique across all AWS accounts.", examples=[ "059f36b4-87a3-44ab-83d2-661975830a7d", "2e1424d4-f796-459a-8184-9c92662be6da", @@ -142,7 +142,7 @@ class SqsRecordModel(BaseModel): ) md5OfMessageAttributes: Optional[str] = Field( default=None, - description="An MD5 digest of the non-URL-encoded message attribute string. You can use this attribute to verify that Amazon SQS received the message correctly.", + description="An MD5 digest of the non-URL-encoded message attribute string.", examples=[ "00484c68...59e48fb7", "b25f48e8...f4e4f0bb",