Skip to content

Commit 4bee949

Browse files
#7123 Tech debt: Improve documentation of Event model fields in DynamoDB parser models
1 parent 17073d8 commit 4bee949

File tree

1 file changed

+112
-32
lines changed
  • aws_lambda_powertools/utilities/parser/models

1 file changed

+112
-32
lines changed

aws_lambda_powertools/utilities/parser/models/dynamodb.py

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

5-
from pydantic import BaseModel, field_validator
6-
5+
from pydantic import BaseModel, Field, field_validator
76
from aws_lambda_powertools.shared.dynamodb_deserializer import TypeDeserializer
87

98
_DESERIALIZER = TypeDeserializer()
109

1110

1211
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
12+
ApproximateCreationDateTime: Optional[float] = Field( # AWS sends this as Unix epoch float
13+
default=None,
14+
description="The approximate date and time when the stream record was created (Unix epoch time).",
15+
examples=[1693997155.0]
16+
)
17+
Keys: Dict[str, Any] = Field(
18+
description="Primary key attributes for the item.",
19+
examples=[{"Id": {"N": "101"}}]
20+
)
21+
NewImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = Field(
22+
default=None,
23+
description="The item after modifications, in DynamoDB attribute-value format.",
24+
examples=[{
25+
"Message": {"S": "New item!"},
26+
"Id": {"N": "101"}
27+
}]
28+
)
29+
OldImage: Optional[Union[Dict[str, Any], Type[BaseModel], BaseModel]] = Field(
30+
default=None,
31+
description="The item before modifications, in DynamoDB attribute-value format.",
32+
examples=[{
33+
"Message": {"S": "Old item!"},
34+
"Id": {"N": "100"}
35+
}]
36+
)
37+
SequenceNumber: str = Field(
38+
description="A unique identifier for the stream record.",
39+
examples=["222"]
40+
)
41+
SizeBytes: int = Field(
42+
description="The size of the stream record, in bytes.",
43+
examples=[26]
44+
)
45+
StreamViewType: Literal["NEW_AND_OLD_IMAGES", "KEYS_ONLY", "NEW_IMAGE", "OLD_IMAGE"] = Field(
46+
description="The type of data included in the stream record.",
47+
examples=["NEW_AND_OLD_IMAGES"]
48+
)
3149

3250
@field_validator("Keys", "NewImage", "OldImage", mode="before")
3351
def deserialize_field(cls, value):
34-
return {k: _DESERIALIZER.deserialize(v) for k, v in value.items()}
52+
return {k: _DESERIALIZER.deserialize(v) for k, v in value.items()} if value else value
3553

3654

3755
class UserIdentity(BaseModel):
38-
type: Literal["Service"] # noqa: VNE003, A003
39-
principalId: Literal["dynamodb.amazonaws.com"]
56+
type: Literal["Service"] = Field(
57+
default="Service",
58+
description="The type of identity that made the request, which is always 'Service' for DynamoDB streams.",
59+
examples=["Service"]
60+
)
61+
principalId: str = Field(
62+
description="The unique identifier for the principal that made the request.",
63+
examples=["dynamodb.amazonaws.com"]
64+
)
4065

4166

4267
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
68+
eventID: str = Field(
69+
description="A unique identifier for the event.",
70+
examples=["1"]
71+
)
72+
eventName: Literal["INSERT", "MODIFY", "REMOVE"] = Field(
73+
description="The type of operation that was performed on the item.",
74+
examples=["INSERT"]
75+
)
76+
eventVersion: str = Field(
77+
default="1.0",
78+
description="The version of the stream record format.",
79+
examples=["1.0"]
80+
)
81+
eventSource: str = Field(
82+
default="aws:dynamodb",
83+
description="The source of the event, which is always 'aws:dynamodb' for DynamoDB streams.",
84+
examples=["aws:dynamodb"]
85+
)
86+
awsRegion: str = Field(
87+
description="The AWS region where the stream record was generated.",
88+
examples=["us-west-2"]
89+
)
90+
eventSourceARN: str = Field(
91+
description="The Amazon Resource Name (ARN) of the DynamoDB stream.",
92+
examples=["arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000"]
93+
)
94+
dynamodb: DynamoDBStreamChangedRecordModel = Field(
95+
description="Contains the details of the DynamoDB stream record.",
96+
examples=[{
97+
"ApproximateCreationDateTime": 1693997155.0,
98+
"Keys": {"Id": {"N": "101"}},
99+
"NewImage": {"Message": {"S": "New item!"}, "Id": {"N": "101"}},
100+
"OldImage": {"Message": {"S": "Old item!"}, "Id": {"N": "100"}},
101+
"SequenceNumber": "222",
102+
"SizeBytes": 26,
103+
"StreamViewType": "NEW_AND_OLD_IMAGES"
104+
}]
105+
)
106+
userIdentity: Optional[UserIdentity] = Field(
107+
default=None,
108+
description="Information about the identity that made the request.",
109+
examples=[{"type": "Service", "principalId": "dynamodb.amazonaws.com"}]
110+
)
51111

52112

53113
class DynamoDBStreamModel(BaseModel):
54-
Records: List[DynamoDBStreamRecordModel]
114+
Records: List[DynamoDBStreamRecordModel] = Field(
115+
description="A list of records that contain the details of the DynamoDB stream events.",
116+
examples=[{
117+
"eventID": "1",
118+
"eventName": "INSERT",
119+
"eventVersion": "1.0",
120+
"eventSource": "aws:dynamodb",
121+
"awsRegion": "us-west-2",
122+
"eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/ExampleTable/stream/2021-01-01T00:00:00.000",
123+
"dynamodb": {
124+
"ApproximateCreationDateTime": 1693997155.0,
125+
"Keys": {"Id": {"N": "101"}},
126+
"NewImage": {"Message": {"S": "New item!"}, "Id": {"N": "101"}},
127+
"OldImage": {"Message": {"S": "Old item!"}, "Id": {"N": "100"}},
128+
"SequenceNumber": "222",
129+
"SizeBytes": 26,
130+
"StreamViewType": "NEW_AND_OLD_IMAGES"
131+
},
132+
"userIdentity": {"type": "Service", "principalId": "dynamodb.amazonaws.com"}
133+
}]
134+
)

0 commit comments

Comments
 (0)