🪖

Go言語でDynamoDBを操作してみた

2024/03/17に公開

前職のときに少しだけ触ってたGo言語を触ってみたくなって、その流れでDynamoDBを操作してみたのでそのメモです。

使用したバージョン

  • Go言語: 1.22.0

AWS SDKのインストール

まずはAWSのSDKをインストールします。

インストールは以下のコマンドで行います。

go get github.com/aws/aws-sdk-go-v2/aws
go get github.com/aws/aws-sdk-go-v2/config
go get github.com/aws/aws-sdk-go-v2/service/dynamodb
go get github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue

テーブルの作成

まずはDynamoDBのテーブルを作成します。今回は東京リージョンで作成します。

テーブル名は dynamo-golang-sampleで、パーティションキーは idとします。

他の設定はデフォルトのままで作成します。

アイテムをCRUDするコード

以下のコードで一通りCRUD操作を行います。

package main

import (
	"context"
	"log"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
	"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

type TableItem struct {
	ID   string `dynamodbav:"id"`
	Name string `dynamodbav:"name"`
}

type ItemKey struct {
	ID string `dynamodbav:"id"`
}

func main() {
	cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("ap-northeast-1"))
	if err != nil {
		log.Fatal(err)
	}

	client := dynamodb.NewFromConfig(cfg)

	// データを追加
	log.Println("put item")
	item := TableItem{
		ID:   "user1",
		Name: "taro",
	}
	av, err := attributevalue.MarshalMap(item)
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.PutItem(context.TODO(), &dynamodb.PutItemInput{
		TableName: aws.String("dynamo-golang-sample"),
		Item:      av,
	})
	if err != nil {
		log.Fatal(err)
	}

	// データを取得
	log.Println("get item")
	itemKey := ItemKey{
		ID: "user1",
	}
	av, err = attributevalue.MarshalMap(itemKey)
	if err != nil {
		log.Fatal(err)
	}

	res, err := client.GetItem(context.TODO(), &dynamodb.GetItemInput{
		TableName: aws.String("dynamo-golang-sample"),
		Key:       av,
	})
	if err != nil {
		log.Fatal(err)
	}

	// 取得したアイテムを構造体に変換
	item = TableItem{}
	err = attributevalue.UnmarshalMap(res.Item, &item)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("id:", item.ID, "name:", item.Name)

	// データを更新
	log.Println("update item")
	item = TableItem{
		ID:   "user1",
		Name: "jiro",
	}
	av, err = attributevalue.MarshalMap(item)
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.PutItem(context.TODO(), &dynamodb.PutItemInput{
		TableName: aws.String("dynamo-golang-sample"),
		Item:      av,
	})
	if err != nil {
		log.Fatal(err)
	}

	// 更新したデータを取得
	log.Println("get updated item")
	itemKey = ItemKey{
		ID: "user1",
	}
	av, err = attributevalue.MarshalMap(itemKey)
	if err != nil {
		log.Fatal(err)
	}

	res, err = client.GetItem(context.TODO(), &dynamodb.GetItemInput{
		TableName: aws.String("dynamo-golang-sample"),
		Key:       av,
	})
	if err != nil {
		log.Fatal(err)
	}

	item = TableItem{}
	err = attributevalue.UnmarshalMap(res.Item, &item)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("id:", item.ID, "name:", item.Name)

	// データを削除
	log.Println("delete item")
	av, err = attributevalue.MarshalMap(itemKey)
	if err != nil {
		log.Fatal(err)
	}

	_, err = client.DeleteItem(context.TODO(), &dynamodb.DeleteItemInput{
		TableName: aws.String("dynamo-golang-sample"),
		Key:       av,
	})
	if err != nil {
		log.Fatal(err)
	}
}

詰まったところ

サンプルを探してたら、以下のように dynamodb.AttributeValueを使っている事例をよく見かけたので試したのですが、undefinedでエラーになって原因がわからずハマりました。

res, err = client.GetItem(context.TODO(), &dynamodb.GetItemInput{
    TableName: aws.String("dynamo-golang-sample"),
    Key: map[string]dynamodb.AttributeValue{
        "id": &dynamodb.AttributeValue{
            S: aws.String("user1"),
        },
    },
    AttributesToGet: []string{
        *aws.String("id"),
    },
})

で、よくよくソースコードを見てたら、↑の書き方はv1の書き方だということにこの記事を書いているときに気づきました。

まとめ

今回はGo言語を使ってDynamoDBを操作してみました。

今までスクリプト言語ばかり触っていて、静的型付け言語を触ると結構戸惑いがありましたがGo言語はその中でも割と書きやすいと感じました。

Go言語をおすすめする人たちの気持ちが少しわかった気がします。

Discussion