Skip to content

Commit 45525e0

Browse files
authored
Add SQS API event structs (awslabs#711)
Adds strucs to allow serializing data coming from the AWS SQS API. Fixes awslabs#710 Signed-off-by: Rémy Greinhofer <[email protected]>
1 parent b9d64e8 commit 45525e0

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

lambda-events/src/event/sqs/mod.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,74 @@ pub struct BatchItemFailure {
112112
pub item_identifier: String,
113113
}
114114

115+
/// The Event sent to Lambda from the SQS API. Contains 1 or more individual SQS Messages
116+
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
117+
#[serde(rename_all = "PascalCase")]
118+
#[serde(bound(deserialize = "T: DeserializeOwned"))]
119+
pub struct SqsApiEventObj<T: Serialize> {
120+
#[serde(bound(deserialize = "T: DeserializeOwned"))]
121+
pub messages: Vec<SqsApiMessageObj<T>>,
122+
}
123+
124+
/// The Event sent to Lambda from SQS API. Contains 1 or more individual SQS Messages
125+
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
126+
#[serde(rename_all = "camelCase")]
127+
pub struct SqsApiEvent {
128+
pub messages: Vec<SqsApiMessage>,
129+
}
130+
131+
/// Alternative to SqsApiEvent to be used alongside SqsApiMessageObj<T> when you need to
132+
/// deserialize a nested object into a struct of type T within the SQS Message rather
133+
/// than just using the raw SQS Message string
134+
#[serde_with::serde_as]
135+
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
136+
#[serde(bound(deserialize = "T: DeserializeOwned"))]
137+
#[serde(rename_all = "PascalCase")]
138+
pub struct SqsApiMessageObj<T: Serialize> {
139+
/// nolint: stylecheck
140+
#[serde(default)]
141+
pub message_id: Option<String>,
142+
#[serde(default)]
143+
pub receipt_handle: Option<String>,
144+
/// Deserialized into a `T` from nested JSON inside the SQS body string. `T` must implement the `Deserialize` or `DeserializeOwned` trait.
145+
#[serde_as(as = "serde_with::json::JsonString")]
146+
#[serde(bound(deserialize = "T: DeserializeOwned"))]
147+
pub body: T,
148+
#[serde(default)]
149+
pub md5_of_body: Option<String>,
150+
#[serde(default)]
151+
pub md5_of_message_attributes: Option<String>,
152+
#[serde(deserialize_with = "deserialize_lambda_map")]
153+
#[serde(default)]
154+
pub attributes: HashMap<String, String>,
155+
#[serde(deserialize_with = "deserialize_lambda_map")]
156+
#[serde(default)]
157+
pub message_attributes: HashMap<String, SqsMessageAttribute>,
158+
}
159+
160+
/// An individual SQS API Message, its metadata, and Message Attributes
161+
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
162+
#[serde(rename_all = "PascalCase")]
163+
pub struct SqsApiMessage {
164+
/// nolint: stylecheck
165+
#[serde(default)]
166+
pub message_id: Option<String>,
167+
#[serde(default)]
168+
pub receipt_handle: Option<String>,
169+
#[serde(default)]
170+
pub body: Option<String>,
171+
#[serde(default)]
172+
pub md5_of_body: Option<String>,
173+
#[serde(default)]
174+
pub md5_of_message_attributes: Option<String>,
175+
#[serde(deserialize_with = "deserialize_lambda_map")]
176+
#[serde(default)]
177+
pub attributes: HashMap<String, String>,
178+
#[serde(deserialize_with = "deserialize_lambda_map")]
179+
#[serde(default)]
180+
pub message_attributes: HashMap<String, SqsMessageAttribute>,
181+
}
182+
115183
#[cfg(test)]
116184
mod test {
117185
use super::*;
@@ -159,4 +227,26 @@ mod test {
159227
let reparsed: SqsBatchResponse = serde_json::from_slice(output.as_bytes()).unwrap();
160228
assert_eq!(parsed, reparsed);
161229
}
230+
231+
#[test]
232+
#[cfg(feature = "sqs")]
233+
fn example_sqs_api_obj_event() {
234+
// Example sqs api receive message response, fetched 2023-10-23, inspired from:
235+
// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html#API_ReceiveMessage_ResponseSyntax
236+
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
237+
struct CustStruct {
238+
city: String,
239+
country: String,
240+
}
241+
242+
let data = include_bytes!("../../fixtures/example-sqs-api-event-obj.json");
243+
let parsed: SqsApiEventObj<CustStruct> = serde_json::from_slice(data).unwrap();
244+
245+
assert_eq!(parsed.messages[0].body.city, "provincetown");
246+
assert_eq!(parsed.messages[0].body.country, "usa");
247+
248+
let output: String = serde_json::to_string(&parsed).unwrap();
249+
let reparsed: SqsApiEventObj<CustStruct> = serde_json::from_slice(output.as_bytes()).unwrap();
250+
assert_eq!(parsed, reparsed);
251+
}
162252
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Messages": [
3+
{
4+
"Body": "{\"country\": \"usa\", \"city\": \"provincetown\"}",
5+
"Md5OfBody": "2b3e4f40b57e80d67ac5b9660c56d787",
6+
"MessageId": "f663a189-97e2-41f5-9c0e-cfb595d8322c",
7+
"ReceiptHandle": "AQEBdObBZIl7FWJiK9c3KmqKNvusy6+eqG51SLIp5Gs6lQ6+e4SI0lJ6Glw+qcOi+2RRrnfOjlsF8uDlo13TgubmtgP+CH7s+YKDdpbg2jA931vLi6qnU0ZFXcf/H8BDZ4kcz29npMu9/N2DT9F+kI9Q9pTfLsISg/7XFMvRTqAtjSfa2wI5TVcOPZBdkGqTLUoKqAYni0L7NTLzFUTjCN/HiOcvG+16zahhsTniM1MwOTSpbOO2uTZmY25V/PCfNdF1PBXtdNA9mWW2Ym6THV28ug3cuK6dXbFQBuxIGVhOq+mRVU6gKN/eZpZediiBt75oHD6ASu8jIUpJGeUWEZm6qSWU+YTivr6QoqGLwAVvI3CXOIZQ/+Wp/RJAxMQxtRIe/MOsOITcmGlFqhWnjlGQdg=="
8+
}
9+
]
10+
}

0 commit comments

Comments
 (0)