Skip to content

Commit d670b6d

Browse files
refactor(parser): Improve DynamoDB models with examples and descriptions (#7146)
* #7123 Tech debt: Improve documentation of Event model fields in DynamoDB parser models * refactor(parser): address PR review feedback for DynamoDB models * Addressing changes --------- Co-authored-by: Leandro Damascena <[email protected]>
1 parent 5a4b2a0 commit d670b6d

File tree

1 file changed

+88
-30
lines changed
  • aws_lambda_powertools/utilities/parser/models

1 file changed

+88
-30
lines changed

aws_lambda_powertools/utilities/parser/models/dynamodb.py

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,111 @@
22
from datetime import datetime
33
from typing import Any, Dict, List, Literal, Optional, Type, Union
44

5-
from pydantic import BaseModel, field_validator
5+
from pydantic import BaseModel, Field, field_validator
66

77
from aws_lambda_powertools.shared.dynamodb_deserializer import TypeDeserializer
88

99
_DESERIALIZER = TypeDeserializer()
1010

1111

1212
class DynamoDBStreamChangedRecordModel(BaseModel):
13-
ApproximateCreationDateTime: Optional[datetime] = None
14-
Keys: Dict[str, Any]
15-
NewImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = None
16-
OldImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = None
17-
SequenceNumber: str
18-
SizeBytes: int
19-
StreamViewType: Literal["NEW_AND_OLD_IMAGES", "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE"]
20-
21-
# context on why it's commented: https://github.com/aws-powertools/powertools-lambda-python/pull/118
22-
# since both images are optional, they can both be None. However, at least one must
23-
# exist in a legal model of NEW_AND_OLD_IMAGES type
24-
# @root_validator
25-
# def check_one_image_exists(cls, values): # noqa: ERA001
26-
# new_img, old_img = values.get("NewImage"), values.get("OldImage") # noqa: ERA001
27-
# stream_type = values.get("StreamViewType") # noqa: ERA001
28-
# if stream_type == "NEW_AND_OLD_IMAGES" and not new_img and not old_img: # noqa: ERA001
29-
# raise TypeError("DynamoDB streams model failed validation, missing both new & old stream images") # noqa: ERA001,E501
30-
# return values # noqa: ERA001
13+
ApproximateCreationDateTime: Optional[datetime] = Field( # AWS sends this as Unix epoch float
14+
default=None,
15+
description="The approximate date and time when the stream record was created (Unix epoch time).",
16+
examples=[1693997155.0],
17+
)
18+
Keys: Dict[str, Any] = Field(description="Primary key attributes for the item.", examples=[{"Id": {"N": "101"}}])
19+
NewImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = Field(
20+
default=None,
21+
description="The item after modifications, in DynamoDB attribute-value format.",
22+
examples=[{"Message": {"S": "New item!"}, "Id": {"N": "101"}}],
23+
)
24+
OldImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = Field(
25+
default=None,
26+
description="The item before modifications, in DynamoDB attribute-value format.",
27+
examples=[{"Message": {"S": "Old item!"}, "Id": {"N": "100"}}],
28+
)
29+
SequenceNumber: str = Field(description="A unique identifier for the stream record.", examples=["222"])
30+
SizeBytes: int = Field(description="The size of the stream record, in bytes.", examples=[26])
31+
StreamViewType: Literal["NEW_AND_OLD_IMAGES", "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE"] = Field(
32+
description="The type of data included in the stream record.",
33+
examples=["NEW_AND_OLD_IMAGES"],
34+
)
3135

3236
@field_validator("Keys", "NewImage", "OldImage", mode="before")
3337
def deserialize_field(cls, value):
3438
return {k: _DESERIALIZER.deserialize(v) for k, v in value.items()}
3539

3640

3741
class UserIdentity(BaseModel):
38-
type: Literal["Service"] # noqa: VNE003, A003
39-
principalId: Literal["dynamodb.amazonaws.com"]
42+
type: Literal["Service"] = Field(
43+
description="The type of identity that made the request, which is always 'Service' for DynamoDB streams.",
44+
examples=["Service"],
45+
)
46+
principalId: Literal["dynamodb.amazonaws.com"] = Field(
47+
description="The unique identifier for the principal that made the request.",
48+
examples=["dynamodb.amazonaws.com"],
49+
)
4050

4151

4252
class DynamoDBStreamRecordModel(BaseModel):
43-
eventID: str
44-
eventName: Literal["INSERT", "MODIFY", "REMOVE"]
45-
eventVersion: float
46-
eventSource: Literal["aws:dynamodb"]
47-
awsRegion: str
48-
eventSourceARN: str
49-
dynamodb: DynamoDBStreamChangedRecordModel
50-
userIdentity: Optional[UserIdentity] = None
53+
eventID: str = Field(description="A unique identifier for the event.", examples=["1"])
54+
eventName: Literal["INSERT", "MODIFY", "REMOVE"] = Field(
55+
description="The type of operation that was performed on the item.",
56+
examples=["INSERT"],
57+
)
58+
eventVersion: float = Field(description="The version of the stream record format.", examples=["1.0"])
59+
eventSource: Literal["aws:dynamodb"] = Field(
60+
description="The source of the event, which is always 'aws:dynamodb' for DynamoDB streams.",
61+
examples=["aws:dynamodb"],
62+
)
63+
awsRegion: str = Field(description="The AWS region where the stream record was generated.", examples=["us-west-2"])
64+
eventSourceARN: str = Field(
65+
description="The Amazon Resource Name (ARN) of the DynamoDB stream.",
66+
examples=["arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000"],
67+
)
68+
dynamodb: DynamoDBStreamChangedRecordModel = Field(
69+
description="Contains the details of the DynamoDB stream record.",
70+
examples=[
71+
{
72+
"ApproximateCreationDateTime": 1693997155.0,
73+
"Keys": {"Id": {"N": "101"}},
74+
"NewImage": {"Message": {"S": "New item!"}, "Id": {"N": "101"}},
75+
"OldImage": {"Message": {"S": "Old item!"}, "Id": {"N": "100"}},
76+
"SequenceNumber": "222",
77+
"SizeBytes": 26,
78+
"StreamViewType": "NEW_AND_OLD_IMAGES",
79+
},
80+
],
81+
)
82+
userIdentity: Optional[UserIdentity] = Field(
83+
default=None,
84+
description="Information about the identity that made the request.",
85+
examples=[{"type": "Service", "principalId": "dynamodb.amazonaws.com"}],
86+
)
5187

5288

5389
class DynamoDBStreamModel(BaseModel):
54-
Records: List[DynamoDBStreamRecordModel]
90+
Records: List[DynamoDBStreamRecordModel] = Field(
91+
description="A list of records that contain the details of the DynamoDB stream events.",
92+
examples=[
93+
{
94+
"eventID": "1",
95+
"eventName": "INSERT",
96+
"eventVersion": "1.0",
97+
"eventSource": "aws:dynamodb",
98+
"awsRegion": "us-west-2",
99+
"eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000", # noqa E501
100+
"dynamodb": {
101+
"ApproximateCreationDateTime": 1693997155.0,
102+
"Keys": {"Id": {"N": "101"}},
103+
"NewImage": {"Message": {"S": "New item!"}, "Id": {"N": "101"}},
104+
"OldImage": {"Message": {"S": "Old item!"}, "Id": {"N": "100"}},
105+
"SequenceNumber": "222",
106+
"SizeBytes": 26,
107+
"StreamViewType": "NEW_AND_OLD_IMAGES",
108+
},
109+
"userIdentity": {"type": "Service", "principalId": "dynamodb.amazonaws.com"},
110+
},
111+
],
112+
)

0 commit comments

Comments
 (0)