Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add SQS API event structs
Adds strucs to allow serializing data coming from the AWS SQS API.

Fixes #710

Signed-off-by: Rémy Greinhofer <[email protected]>
  • Loading branch information
rgreinho committed Oct 23, 2023
commit 88f620ebcf7be4d685140a4dc79038fbdafe9b25
90 changes: 90 additions & 0 deletions lambda-events/src/event/sqs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,74 @@ pub struct BatchItemFailure {
pub item_identifier: String,
}

/// The Event sent to Lambda from the SQS API. Contains 1 or more individual SQS Messages
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
#[serde(bound(deserialize = "T: DeserializeOwned"))]
pub struct SqsApiEventObj<T: Serialize> {
#[serde(bound(deserialize = "T: DeserializeOwned"))]
pub messages: Vec<SqsApiMessageObj<T>>,
}

/// The Event sent to Lambda from SQS API. Contains 1 or more individual SQS Messages
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SqsApiEvent {
pub messages: Vec<SqsApiMessage>,
}

/// Alternative to SqsApiEvent to be used alongside SqsApiMessageObj<T> when you need to
/// deserialize a nested object into a struct of type T within the SQS Message rather
/// than just using the raw SQS Message string
#[serde_with::serde_as]
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(bound(deserialize = "T: DeserializeOwned"))]
#[serde(rename_all = "PascalCase")]
pub struct SqsApiMessageObj<T: Serialize> {
/// nolint: stylecheck
#[serde(default)]
pub message_id: Option<String>,
#[serde(default)]
pub receipt_handle: Option<String>,
/// Deserialized into a `T` from nested JSON inside the SQS body string. `T` must implement the `Deserialize` or `DeserializeOwned` trait.
#[serde_as(as = "serde_with::json::JsonString")]
#[serde(bound(deserialize = "T: DeserializeOwned"))]
pub body: T,
#[serde(default)]
pub md5_of_body: Option<String>,
#[serde(default)]
pub md5_of_message_attributes: Option<String>,
#[serde(deserialize_with = "deserialize_lambda_map")]
#[serde(default)]
pub attributes: HashMap<String, String>,
#[serde(deserialize_with = "deserialize_lambda_map")]
#[serde(default)]
pub message_attributes: HashMap<String, SqsMessageAttribute>,
}

/// An individual SQS API Message, its metadata, and Message Attributes
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct SqsApiMessage {
/// nolint: stylecheck
#[serde(default)]
pub message_id: Option<String>,
#[serde(default)]
pub receipt_handle: Option<String>,
#[serde(default)]
pub body: Option<String>,
#[serde(default)]
pub md5_of_body: Option<String>,
#[serde(default)]
pub md5_of_message_attributes: Option<String>,
#[serde(deserialize_with = "deserialize_lambda_map")]
#[serde(default)]
pub attributes: HashMap<String, String>,
#[serde(deserialize_with = "deserialize_lambda_map")]
#[serde(default)]
pub message_attributes: HashMap<String, SqsMessageAttribute>,
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -159,4 +227,26 @@ mod test {
let reparsed: SqsBatchResponse = serde_json::from_slice(output.as_bytes()).unwrap();
assert_eq!(parsed, reparsed);
}

#[test]
#[cfg(feature = "sqs")]
fn example_sqs_api_obj_event() {
// Example sqs api receive message response, fetched 2023-10-23, inspired from:
// https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html#API_ReceiveMessage_ResponseSyntax
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct CustStruct {
city: String,
country: String,
}

let data = include_bytes!("../../fixtures/example-sqs-api-event-obj.json");
let parsed: SqsApiEventObj<CustStruct> = serde_json::from_slice(data).unwrap();

assert_eq!(parsed.messages[0].body.city, "provincetown");
assert_eq!(parsed.messages[0].body.country, "usa");

let output: String = serde_json::to_string(&parsed).unwrap();
let reparsed: SqsApiEventObj<CustStruct> = serde_json::from_slice(output.as_bytes()).unwrap();
assert_eq!(parsed, reparsed);
}
}
10 changes: 10 additions & 0 deletions lambda-events/src/fixtures/example-sqs-api-event-obj.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Messages": [
{
"Body": "{\"country\": \"usa\", \"city\": \"provincetown\"}",
"Md5OfBody": "2b3e4f40b57e80d67ac5b9660c56d787",
"MessageId": "f663a189-97e2-41f5-9c0e-cfb595d8322c",
"ReceiptHandle": "AQEBdObBZIl7FWJiK9c3KmqKNvusy6+eqG51SLIp5Gs6lQ6+e4SI0lJ6Glw+qcOi+2RRrnfOjlsF8uDlo13TgubmtgP+CH7s+YKDdpbg2jA931vLi6qnU0ZFXcf/H8BDZ4kcz29npMu9/N2DT9F+kI9Q9pTfLsISg/7XFMvRTqAtjSfa2wI5TVcOPZBdkGqTLUoKqAYni0L7NTLzFUTjCN/HiOcvG+16zahhsTniM1MwOTSpbOO2uTZmY25V/PCfNdF1PBXtdNA9mWW2Ym6THV28ug3cuK6dXbFQBuxIGVhOq+mRVU6gKN/eZpZediiBt75oHD6ASu8jIUpJGeUWEZm6qSWU+YTivr6QoqGLwAVvI3CXOIZQ/+Wp/RJAxMQxtRIe/MOsOITcmGlFqhWnjlGQdg=="
}
]
}