RustのAWS SDKがGAになったので早速触ってみる！

2023/11にAWS SDK for Rustの一般提供が開始されたようでした！

- [AWS SDK for Rust の一般提供を開始](https://aws.amazon.com/jp/about-aws/whats-new/2023/11/aws-sdk-rust/)
- [[速報] AWS SDK for RustがGAになりました！ #AWSreInvent](https://dev.classmethod.jp/articles/aws-sdk-for-rust-ga/)

最近はRustしか触っておらず、CLIツールやWebAPIなどで今後S3をRustから利用することもあろうと思い、ちょっとだけ触ってみました！

## まずは情報を眺めてみる

さすがAWS！という感じで、情報はそれなりに豊富にあるようでした！

- 基礎的な情報
    - [Rust用AWS SDK](https://aws.amazon.com/jp/sdk-for-rust/?pg=devrust)
    - [APIリファレンス](https://awslabs.github.io/aws-sdk-rust/)
    - [SDK for Rust code examples](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_code_examples.html)
    - [examples用のリポジトリ](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main)

今回は以下を参考にしました！

https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/s3#code-examples

## プロジェクトを立ち上げる

コードは以下のリポジトリにアップロードしているので、cloneしてください！

https://github.com/nokonoko1203/rust-aws-sdk-sample

プロジェクトの立ち上げ方はこちらにも記載しています。

https://qiita.com/nokonoko_1203/items/c14b4b4ac0b9649dd8d0

Cargo.tomlは以下のように設定しています。

```rust
[package]
name = "rust-aws"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.79"
aws-config = { version = "1.0.1", features = ["behavior-version-latest"] }
aws-sdk-s3 = { version = "1.4.0", features = ["rt-tokio"] }
tokio = { version = "1.20.1", features = ["full"] }
```

## バケットを作成する

以下のtextを参考にしながら進めていきました！

https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/s3#code-examples

こんなようなコードになりました。

```rust
use anyhow::Error;
use aws_sdk_s3::operation::create_bucket::{CreateBucketError, CreateBucketOutput};
use aws_sdk_s3::types::{BucketLocationConstraint, CreateBucketConfiguration};
use aws_sdk_s3::{error::SdkError, Client};
use std::str;

async fn create_bucket(
    client: &Client,
    bucket_name: &str,
    region: &str,
) -> Result<CreateBucketOutput, SdkError<CreateBucketError>> {
    let constraint = BucketLocationConstraint::from(region);
    let cfg = CreateBucketConfiguration::builder()
        .location_constraint(constraint)
        .build();
    client
        .create_bucket()
        .create_bucket_configuration(cfg)
        .bucket(bucket_name)
        .send()
        .await
}

#[tokio::main]
async fn main() {
    let config = aws_config::load_from_env().await;
    let client = aws_sdk_s3::Client::new(&config);
    let bucket_name = "rust-sdk-test-bucket1";
    let region = "ap-northeast-1";

    let result = create_bucket(&client, bucket_name, region).await;
    match result {
        Ok(output) => println!("Bucket location: {:?}", output.location()),
        Err(error) => println!("Error: {:?}", error),
    }
}
```

やっていることはとてもシンプルですね。

- `anyhow::Error`: エラーハンドリングに使用
- `aws_sdk_s3`など: S3とのやり取りに必要な機能

main（）関数では`#[tokio::main]`を利用し非同期処理を可能にします。

AWSの設定は、環境変数からロードするため、実行時にはターミナルにシークレットキーなどを設定しておく必要があります。

`cargo run`でコマンドを実行してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/9af7feb7-c6b3-9fd6-e1bf-3d50c6a02a01.png)

バケットが作成されました！

## バケットを削除

以下のように削除用のコードを追加してみましょう！

```rust
use anyhow::Error;
use aws_sdk_s3::operation::create_bucket::{CreateBucketError, CreateBucketOutput};
use aws_sdk_s3::types::{BucketLocationConstraint, CreateBucketConfiguration};
use aws_sdk_s3::{error::SdkError, Client};
use std::str;

async fn create_bucket(
    client: &Client,
    bucket_name: &str,
    region: &str,
) -> Result<CreateBucketOutput, SdkError<CreateBucketError>> {
    let constraint = BucketLocationConstraint::from(region);
    let cfg = CreateBucketConfiguration::builder()
        .location_constraint(constraint)
        .build();
    client
        .create_bucket()
        .create_bucket_configuration(cfg)
        .bucket(bucket_name)
        .send()
        .await
}

async fn delete_bucket(client: &Client, bucket_name: &str) -> Result<(), Error> {
    client.delete_bucket().bucket(bucket_name).send().await?;
    Ok(())
}

#[tokio::main]
async fn main() {
    let config = aws_config::load_from_env().await;
    let client = aws_sdk_s3::Client::new(&config);
    let bucket_name = "rust-sdk-test-bucket1";
    let region = "ap-northeast-1";

    let result = create_bucket(&client, bucket_name, region).await;
    match result {
        Ok(output) => println!("Bucket location: {:?}", output.location()),
        Err(error) => println!("Error: {:?}", error),
    }

    let result = delete_bucket(&client, bucket_name).await;
    match result {
        Ok(_) => println!("Bucket deleted"),
        Err(error) => println!("Error: {:?}", error),
    }
}
```

`cargo run`を実行すると、`create_bucket()`関数実行箇所で、すでにバケットが存在するのでエラーが発生しますが、`Bucket deleted`のメッセージが表示されます。

実際に先ほど見ていた画面を更新すると、バケットが削除されたため「不明なエラー」が出ていることがわかります。
（もちろん、一覧からも削除されているはずです。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/30efc48d-b6c4-c8c0-9761-a53b6615c01e.png)

簡単ですね！

## 終わりに

他の言語でAWS SDKを触ったことがあればわかると思いますが、（この程度の作業であれば）全く違和感なく作業することができます！

ガシガシ使っていきましょう！