Skip to content

Commit bcf9aba

Browse files
jeromevdlpankajagrawal16dependabot[bot]
authored
feat: Easy Event Deserialization (#757)
* use serialization lib instead of internal stuff * add ActiveMq & RabbitMQ * feature: easy deserialization of event content * rename methods in deserializer * Update powertools-serialization/src/test/java/software/amazon/lambda/powertools/utilities/EventDeserializerTest.java Co-authored-by: Pankaj Agrawal <[email protected]> * chore: remove SQS and Idempotency examples (#754) * build(deps): bump maven-jar-plugin from 3.2.0 to 3.2.2 (#756) Bumps [maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.2.0 to 3.2.2. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](apache/maven-jar-plugin@maven-jar-plugin-3.2.0...maven-jar-plugin-3.2.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump aws.sdk.version from 2.17.130 to 2.17.131 (#755) Bumps `aws.sdk.version` from 2.17.130 to 2.17.131. Updates `software.amazon.awssdk:bom` from 2.17.130 to 2.17.131 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](aws/aws-sdk-java-v2@2.17.130...2.17.131) Updates `http-client-spi` from 2.17.130 to 2.17.131 - [Release notes](https://github.com/aws/aws-sdk-java-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-java-v2/blob/master/CHANGELOG.md) - [Commits](aws/aws-sdk-java-v2@2.17.130...2.17.131) Updates `url-connection-client` from 2.17.130 to 2.17.131 --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: software.amazon.awssdk:http-client-spi dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: software.amazon.awssdk:url-connection-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix #758 (#759) remove trailing slash for multiple params * changes post review: - javadoc - indentation - better edge cases handling * add tests for edge cases * exception messages detailed * deserialize a string as list * documentation * gradle example Co-authored-by: Pankaj Agrawal <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent b95cf64 commit bcf9aba

File tree

22 files changed

+1125
-17
lines changed

22 files changed

+1125
-17
lines changed

docs/utilities/serialization.md

+243-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,249 @@ title: Serialization Utilities
33
description: Utility
44
---
55

6-
This module contains a set of utilities you may use in your Lambda functions, mainly associated with other modules like [validation](validation.md) and [idempotency](idempotency.md), to manipulate JSON.
6+
This module contains a set of utilities you may use in your Lambda functions, to manipulate JSON.
7+
8+
## Easy deserialization
9+
10+
### Key features
11+
12+
* Easily deserialize the main content of an event (for example, the body of an API Gateway event)
13+
* 15+ built-in events (see the [list below](#built-in-events))
14+
15+
### Getting started
16+
17+
=== "Maven"
18+
19+
```xml hl_lines="5"
20+
<dependencies>
21+
...
22+
<dependency>
23+
<groupId>software.amazon.lambda</groupId>
24+
<artifactId>powertools-serialization</artifactId>
25+
<version>{{ powertools.version }}</version>
26+
</dependency>
27+
...
28+
</dependencies>
29+
```
30+
31+
=== "Gradle"
32+
33+
```
34+
implementation 'software.amazon.lambda:powertools-serialization:{{ powertools.version }}'
35+
```
36+
37+
### EventDeserializer
38+
39+
The `EventDeserializer` can be used to extract the main part of an event (body, message, records) and deserialize it from JSON to your desired type.
40+
41+
It can handle single elements like the body of an API Gateway event:
42+
43+
=== "APIGWHandler.java"
44+
45+
```java hl_lines="1 6 9"
46+
import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom;
47+
48+
public class APIGWHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
49+
50+
public APIGatewayProxyResponseEvent handleRequest(
51+
final APIGatewayProxyRequestEvent event,
52+
final Context context) {
53+
54+
Product product = extractDataFrom(event).as(Product.class);
55+
56+
}
57+
```
58+
59+
=== "Product.java"
60+
61+
```java
62+
public class Product {
63+
private long id;
64+
private String name;
65+
private double price;
66+
67+
public Product() {
68+
}
69+
70+
public Product(long id, String name, double price) {
71+
this.id = id;
72+
this.name = name;
73+
this.price = price;
74+
}
75+
76+
public long getId() {
77+
return id;
78+
}
79+
80+
public void setId(long id) {
81+
this.id = id;
82+
}
83+
84+
public String getName() {
85+
return name;
86+
}
87+
88+
public void setName(String name) {
89+
this.name = name;
90+
}
91+
92+
public double getPrice() {
93+
return price;
94+
}
95+
96+
public void setPrice(double price) {
97+
this.price = price;
98+
}
99+
}
100+
```
101+
102+
=== "event"
103+
104+
```json hl_lines="2"
105+
{
106+
"body": "{\"id\":1234, \"name\":\"product\", \"price\":42}",
107+
"resource": "/{proxy+}",
108+
"path": "/path/to/resource",
109+
"httpMethod": "POST",
110+
"isBase64Encoded": false,
111+
"queryStringParameters": {
112+
"foo": "bar"
113+
},
114+
"pathParameters": {
115+
"proxy": "/path/to/resource"
116+
},
117+
"stageVariables": {
118+
"baz": "qux"
119+
},
120+
"headers": {
121+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
122+
"Accept-Encoding": "gzip, deflate, sdch",
123+
"Accept-Language": "en-US,en;q=0.8",
124+
"Cache-Control": "max-age=0",
125+
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
126+
"Upgrade-Insecure-Requests": "1",
127+
"User-Agent": "Custom User Agent String",
128+
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
129+
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
130+
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
131+
"X-Forwarded-Port": "443",
132+
"X-Forwarded-Proto": "https"
133+
},
134+
"requestContext": {
135+
"accountId": "123456789012",
136+
"resourceId": "123456",
137+
"stage": "prod",
138+
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
139+
"requestTime": "09/Apr/2015:12:34:56 +0000",
140+
"requestTimeEpoch": 1428582896000,
141+
"identity": {
142+
"cognitoIdentityPoolId": null,
143+
"accountId": null,
144+
"cognitoIdentityId": null,
145+
"caller": null,
146+
"accessKey": null,
147+
"sourceIp": "127.0.0.1",
148+
"cognitoAuthenticationType": null,
149+
"cognitoAuthenticationProvider": null,
150+
"userArn": null,
151+
"userAgent": "Custom User Agent String",
152+
"user": null
153+
},
154+
"path": "/prod/path/to/resource",
155+
"resourcePath": "/{proxy+}",
156+
"httpMethod": "POST",
157+
"apiId": "1234567890",
158+
"protocol": "HTTP/1.1"
159+
}
160+
}
161+
```
162+
163+
It can also handle a collection of elements like the records of an SQS event:
164+
165+
=== "SQSHandler.java"
166+
167+
```java hl_lines="1 6 9"
168+
import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom;
169+
170+
public class SQSHandler implements RequestHandler<SQSEvent, String> {
171+
172+
public String handleRequest(
173+
final SQSEvent event,
174+
final Context context) {
175+
176+
List<Product> products = extractDataFrom(event).asListOf(Product.class);
177+
178+
}
179+
```
180+
181+
=== "event"
182+
183+
```json hl_lines="6 23"
184+
{
185+
"Records": [
186+
{
187+
"messageId": "d9144555-9a4f-4ec3-99a0-34ce359b4b54",
188+
"receiptHandle": "13e7f7851d2eaa5c01f208ebadbf1e72==",
189+
"body": "{ \"id\": 1234, \"name\": \"product\", \"price\": 42}",
190+
"attributes": {
191+
"ApproximateReceiveCount": "1",
192+
"SentTimestamp": "1601975706495",
193+
"SenderId": "AROAIFU437PVZ5L2J53F5",
194+
"ApproximateFirstReceiveTimestamp": "1601975706499"
195+
},
196+
"messageAttributes": {
197+
},
198+
"md5OfBody": "13e7f7851d2eaa5c01f208ebadbf1e72",
199+
"eventSource": "aws:sqs",
200+
"eventSourceARN": "arn:aws:sqs:eu-central-1:123456789012:TestLambda",
201+
"awsRegion": "eu-central-1"
202+
},
203+
{
204+
"messageId": "d9144555-9a4f-4ec3-99a0-34ce359b4b54",
205+
"receiptHandle": "13e7f7851d2eaa5c01f208ebadbf1e72==",
206+
"body": "{ \"id\": 12345, \"name\": \"product5\", \"price\": 45}",
207+
"attributes": {
208+
"ApproximateReceiveCount": "1",
209+
"SentTimestamp": "1601975706495",
210+
"SenderId": "AROAIFU437PVZ5L2J53F5",
211+
"ApproximateFirstReceiveTimestamp": "1601975706499"
212+
},
213+
"messageAttributes": {
214+
215+
},
216+
"md5OfBody": "13e7f7851d2eaa5c01f208ebadbf1e72",
217+
"eventSource": "aws:sqs",
218+
"eventSourceARN": "arn:aws:sqs:eu-central-1:123456789012:TestLambda",
219+
"awsRegion": "eu-central-1"
220+
}
221+
]
222+
}
223+
```
224+
225+
!!! Tip
226+
In the background, `EventDeserializer` is using Jackson. The `ObjectMapper` is configured in `JsonConfig`. You can customize the configuration of the mapper if needed:
227+
`JsonConfig.get().getObjectMapper()`. Using this feature, you don't need to add Jackson to your project and create another instance of `ObjectMapper`.
228+
229+
### Built-in events
230+
231+
| Event Type | Path to the content | List |
232+
|---------------------------------------------------|-----------------------------------------------------------|------|
233+
| `APIGatewayProxyRequestEvent` | `body` | |
234+
| `APIGatewayV2HTTPEvent` | `body` | |
235+
| `SNSEvent` | `Records[0].Sns.Message` | |
236+
| `SQSEvent` | `Records[*].body` | x |
237+
| `ScheduledEvent` | `detail` | |
238+
| `ApplicationLoadBalancerRequestEvent` | `body` | |
239+
| `CloudWatchLogsEvent` | `powertools_base64_gzip(data)` | |
240+
| `CloudFormationCustomResourceEvent` | `resourceProperties` | |
241+
| `KinesisEvent` | `Records[*].kinesis.powertools_base64(data)` | x |
242+
| `KinesisFirehoseEvent` | `Records[*].powertools_base64(data)` | x |
243+
| `KafkaEvent` | `records[*].values[*].powertools_base64(value)` | x |
244+
| `ActiveMQEvent` | `messages[*].powertools_base64(data)` | x |
245+
| `RabbitMQEvent` | `rmqMessagesByQueue[*].values[*].powertools_base64(data)` | x |
246+
| `KinesisAnalyticsFirehoseInputPreprocessingEvent` | `Records[*].kinesis.powertools_base64(data)` | x |
247+
| `KinesisAnalyticsStreamsInputPreprocessingEvent` | `Records[*].kinesis.powertools_base64(data)` | x |
248+
7249

8250
## JMESPath functions
9251

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
6565
<lambda.core.version>1.2.1</lambda.core.version>
6666
<lambda.events.version>3.11.0</lambda.events.version>
67+
<lambda.serial.version>1.0.0</lambda.serial.version>
6768
<maven-compiler-plugin.version>3.10.0</maven-compiler-plugin.version>
6869
<aspectj-maven-plugin.version>1.14.0</aspectj-maven-plugin.version>
6970
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
@@ -122,6 +123,11 @@
122123
<artifactId>aws-lambda-java-events</artifactId>
123124
<version>${lambda.events.version}</version>
124125
</dependency>
126+
<dependency>
127+
<groupId>com.amazonaws</groupId>
128+
<artifactId>aws-lambda-java-serialization</artifactId>
129+
<version>${lambda.serial.version}</version>
130+
</dependency>
125131
<dependency>
126132
<groupId>software.amazon.awssdk</groupId>
127133
<artifactId>bom</artifactId>

powertools-serialization/pom.xml

+13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@
4545
<groupId>io.burt</groupId>
4646
<artifactId>jmespath-jackson</artifactId>
4747
</dependency>
48+
<dependency>
49+
<groupId>com.amazonaws</groupId>
50+
<artifactId>aws-lambda-java-events</artifactId>
51+
</dependency>
52+
<dependency>
53+
<groupId>org.apache.logging.log4j</groupId>
54+
<artifactId>log4j-slf4j-impl</artifactId>
55+
</dependency>
4856

4957
<!-- Test dependencies -->
5058
<dependency>
@@ -57,6 +65,11 @@
5765
<artifactId>assertj-core</artifactId>
5866
<scope>test</scope>
5967
</dependency>
68+
<dependency>
69+
<groupId>com.amazonaws</groupId>
70+
<artifactId>aws-lambda-java-tests</artifactId>
71+
<scope>test</scope>
72+
</dependency>
6073
</dependencies>
6174

6275
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates.
3+
* Licensed under the Apache License, Version 2.0 (the
4+
* "License"); you may not use this file except in compliance
5+
* with the License. You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*
13+
*/
14+
package software.amazon.lambda.powertools.utilities;
15+
16+
public class EventDeserializationException extends RuntimeException {
17+
private static final long serialVersionUID = -5003158148870110442L;
18+
19+
public EventDeserializationException(String msg, Exception e) {
20+
super(msg, e);
21+
}
22+
23+
public EventDeserializationException(String msg) {
24+
super(msg);
25+
}
26+
}

0 commit comments

Comments
 (0)