【AWS】SQSからLambdaに送られるJSONのフォーマット

## 起こった問題
RustでLambdaを書いていて、SQSの`MessageAttributes`を含むイベントのjsonをうまくデシリアライズできなかったのでメモ。
>Error: Error("invalid type: map, expected a string", line: 1, column: 710)

AWSのドキュメントにもjsonのサンプルはあるのですが、肝心の`MessageAttributes`の部分が空オブジェクトになっていて中の形式がわかりません。

[チュートリアル: Amazon SQS での Lambda の使用 - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sqs-example.html)
```json
{
    "Records": [
        {
            "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d",
            "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...",
            "body": "test",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1545082649183",
                "SenderId": "AIDAIENQZJOLO23YVJ4VO",
                "ApproximateFirstReceiveTimestamp": "1545082649185"
            },
            "messageAttributes": {},
            "md5OfBody": "098f6bcd4621d373cade4e832627b4f6",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue",
            "awsRegion": "us-east-2"
        }
    ]
}
```

## 正しいフォーマットはこう
MessageAttributesを含めたフォーマットはこうです。
```json
{
  "Records": [
    {
      "messageId" : "MessageID_1",
      "receiptHandle" : "MessageReceiptHandle",
      "body" : "Message Body",
      "md5OfBody" : "fce0ea8dd236ccb3ed9b37dae260836f",
      "md5OfMessageAttributes" : "582c92c5c5b6ac403040a4f3ab3115c9",
      "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:SQSQueue",
      "eventSource": "aws:sqs",
      "awsRegion": "us-west-2",
      "attributes" : {
        "ApproximateReceiveCount" : "2",
        "SentTimestamp" : "1520621625029",
        "SenderId" : "AROAIWPX5BD2BHG722MW4:sender",
        "ApproximateFirstReceiveTimestamp" : "1520621634884"
      },
      "messageAttributes" : {
        "Attribute3" : {
          "binaryValue" : "MTEwMA==",
          "stringListValues" : ["abc", "123"],
          "binaryListValues" : ["MA==", "MQ==", "MA=="],
          "dataType" : "Binary"
        },
        "Attribute2" : {
          "stringValue" : "123",
          "stringListValues" : [ ],
          "binaryListValues" : ["MQ==", "MA=="],
          "dataType" : "Number"
        },
        "Attribute1" : {
          "stringValue" : "AttributeValue1",
          "stringListValues" : [ ],
          "binaryListValues" : [ ],
          "dataType" : "String"
        }
      }
    }
  ]
}
```

Rustでserdeを使ってデシリアライズするならこういう型になります。
```rust
use std::collections::HashMap;
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct SqsEvent {
    pub records: Vec<Record>
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Record {
    #[serde(default)]
    pub message_id: Option<String>,
    #[serde(default)]
    pub receipt_handle: Option<String>,
    #[serde(default)]
    pub body: Option<String>,
    #[serde(default)]
    pub attributes: Option<Attribute>,
    #[serde(default)]
    pub message_attributes: HashMap<String, MessageAttribute>, 
    #[serde(default)]
    pub md5_of_body: Option<String>,
    #[serde(default)]
    pub event_source: Option<String>,
    #[serde(default)]
    pub event_source_a_r_n: Option<String>,
    #[serde(default)]
    pub aws_region: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Attribute {
    #[serde(default)]
    pub approximate_receive_count: Option<String>,
    #[serde(default)]
    pub sent_timestamp: Option<String>,
    #[serde(default)]
    pub sender_id: Option<String>,
    #[serde(default)]
    pub approximate_first_receive_timestamp: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MessageAttribute {
    #[serde(default)]
    pub binary_value: Option<String>,
    #[serde(default)]
    pub string_value: Option<String>,
    #[serde(default)]
    pub string_list_values: Option<Vec<String>>,
    #[serde(default)]
    pub binary_list_values: Option<Vec<String>>,
    #[serde(default)]
    pub data_type: Option<String>,
}
```


## 参考
[aws-lambda-go/sqs-event.json at main · aws/aws-lambda-go](https://github.com/aws/aws-lambda-go/blob/main/events/testdata/sqs-event.json)