AWS SDK for RustでDynamoDBのデータをScanする

[AWS SDK for RustのDeveloper Preview](https://aws.amazon.com/jp/about-aws/whats-new/2021/12/aws-sdk-rust-developer-preview/)が発表されました。

examplesにDynamoDB操作関連のソースコードが載っているので、まずはsacnを試してみたいと思います。

## Scanでデータを取得する

### 検証環境</h3>

* macOS：Big Sur 11.6
* Rust：1.57.0
* AWS SDK for Rust：v0.2.0

### 環境変数の設定

認証情報の取得は環境変数からおこなうため、以下の環境変数を設定します。

* AWS_DEFAULT_REGION
* AWS_SECRET_ACCESS_KEY
* AWS_ACCESS_KEY_ID

詳しくは、[README](https://github.com/awslabs/aws-sdk-rust)で確認してください。


### テーブルの作成

DynamoDBに *Users* テーブルを作成し、スラムダンク 湘北高校のメンバーを登録します。

* テーブル名：Users
* パーティションキー：Id（Number）
* ソートキー：なし

```json:sample-data.json
{
    "users": [
        {
            "Id": 1,
            "Name": "桜木花道",
            "Grade": 1,
            "Position": "PF",
            "Number": 10,
            "Height": 189,
            "Weight": 83
        },
        {
            "Id": 2,
            "Name": "流川楓",
            "Grade": 1,
            "Position": "SF",
            "Number": 11,
            "Height": 187,
            "Weight": 75
        },
        {
            "Id": 3,
            "Name": "赤木剛憲",
            "Grade": 3,
            "Position": "C",
            "Number": 4,
            "Height": 197,
            "Weight": 93
        },
        {
            "Id": 4,
            "Name": "宮城リョータ",
            "Grade": 2,
            "Position": "PG",
            "Number": 7,
            "Height": 168,
            "Weight": 59
        },
        {
            "Id": 5,
            "Name": "三井寿",
            "Grade": 3,
            "Position": "SG",
            "Number": 14,
            "Height": 184,
            "Weight": 70
        },
        {
            "Id": 6,
            "Name": "木暮公延",
            "Grade": 3,
            "Position": "SF",
            "Number": 5,
            "Height": 178,
            "Weight": 62
        }
    ]
}
```

### scanでデータを全件取得する

#### Cargo.toml

依存クレートを設定します。

```toml:Cargo.toml
[dependencies]
aws-config = "0.2.0"
aws-sdk-dynamodb = "0.2.0"
tokio = { version = "1", features = ["full"] }
```

#### main.rs

```rust:main.rs
use aws_sdk_dynamodb::{Client};

#[tokio::main]
async fn main() {
    let config = aws_config::load_from_env().await;
    let client = Client::new(&config);

    let resp = client.scan().table_name("Users").send().await;
    match resp {
        Ok(scan_output) => {
            if let Some(items) = scan_output.items {
                for item in items {
                    println!("{:?}", item);

                    // Idを取り出す
                    if let Some(attr_val) = item.get("Id") {
                        if let Ok(id_val) = attr_val.as_n() {
                            if let Ok(id) = id_val.parse::<u32>() {
                                println!("{}", id);
                            }
                        }
                    }

                    // Nameを取り出す
                    if let Some(attr_val) = item.get("Name") {
                        if let Ok(name) = attr_val.as_s() {
                            println!("{}", name.to_string());
                        }
                    }
                }
            }
        },
        Err(e) => {
            println!("{}", e);
        }
    }
}
```
環境変数に設定した認証情報を取得するため、configを生成します。<br>その後、DynamoDBのクライアントを生成します。

<code>.table_name()</code>でテーブル名を指定し、<code>.send()</code>でリクエストを送信します。<br>非同期メソッドで実装されているため、<code>.await</code>が必要です。

Idの取得では<code>.as_n()</code>、Nameの取得では<code>.as_s()</code>を使用しています。</p>

取得結果のId は<code>&amp;String</code>であるため、<br>数値として扱う場合は<code>.parse()</code>等で変換する必要があるので注意です。

以下、実行結果です。

```
{"Id": N("3"), "Name": S("赤木剛憲"), "Grade": N("3"), "Weight": N("93"), "Height": N("197"), "Position": S("C"), "Number": N("4")}
赤木剛憲
4
{"Id": N("2"), "Number": N("11"), "Position": S("SF"), "Grade": N("1"), "Weight": N("75"), "Name": S("流川楓"), "Height": N("187")}
流川楓
11
{"Height": N("168"), "Weight": N("59"), "Name": S("宮城リョータ"), "Number": N("7"), "Grade": N("2"), "Position": S("PG"), "Id": N("4")}
宮城リョータ
7
{"Position": S("SF"), "Number": N("5"), "Weight": N("62"), "Grade": N("3"), "Name": S("木暮公延"), "Id": N("6"), "Height": N("178")}
木暮公延
5
{"Id": N("1"), "Position": S("PF"), "Height": N("189"), "Number": N("10"), "Grade": N("1"), "Weight": N("83"), "Name": S("桜木花道")}
桜木花道
10
{"Name": S("三井寿"), "Grade": N("3"), "Number": N("14"), "Height": N("184"), "Position": S("SG"), "Id": N("5"), "Weight": N("70")}
三井寿
14
```

### まとめ

リクエストを送信するまでの処理は、直感的でわかりやすいと感じました。

レスポンスの解析が面倒で、どうしてもネストが深くなりがちに...<br>スマートな書き方があれば、教えてください...

---

ブログも書いてます。 遊びにきてください:relieved:

https://dottrail.codemountains.org/aws-sdk-rust-scan/

https://dottrail.codemountains.org/aws-sdk-rust-query/

https://dottrail.codemountains.org/aws-sdk-rust-crud/