📦

【DynamoDB】Dockerで立てたDynamoDB LocalをGoで扱う

2021/10/03に公開

はじめに

DynamoDB Localを簡単に触ってみたので、記事にしてみました。
DynamoDB LocalはCredentials全部ダミーでいいから楽ですね。
また、無料で使えて、キャパシティユニットなども全く気にしなくていいので嬉しいです。
今回はCLIは使わずに、全部コードだけです。

ゴール

docker-compose up 
go run main.go

この2つのコマンドだけで、DynamoDBを触る事が出来ること。

環境

  • go 1.15
  • github.com/aws/aws-sdk-go v1.38.0
  • github.com/guregu/dynamo v1.11.0

前提

こちらはある前提で進めます。
インストールなどは事前にお済ませください。

  • Dockerが扱える環境であること(インストールなどご用意ください)
  • go.mod使用(go mod initなど必要です)
  • "github.com/guregu/dynamo"を使用しています。
    素のaws-sdkの書き方とは違うので、ご注意ください。

では、早速やっていきます。

ソースコード

docker-compose.yml

こちらは公式から丸パクリです。
GoのアプリケーションもDocker化出来ますが、今回はDynamoDB Localだけです。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html

version: '3.8'
services:
  dynamodb-local:
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
    image: "amazon/dynamodb-local:latest"
    container_name: dynamodb-local
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal

main.go

package main

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/guregu/dynamo"
)

type User struct {
	UserID string `dynamo:"UserID,hash"`
	Name   string `dynamo:"Name,range"`
	Age    int    `dynamo:"Age"`
	Text   string `dynamo:"Text"`
}

// 本来はenvから取得した方が良い
const AWS_REGION = "ap-northeast-1"
const DYNAMO_ENDPOINT = "http://localhost:8000"

func main() {
	// クライアントの設定
	sess, err := session.NewSession(&aws.Config{
		Region:      aws.String(AWS_REGION),
		Endpoint:    aws.String(DYNAMO_ENDPOINT),
		Credentials: credentials.NewStaticCredentials("dummy", "dummy", "dummy"),
	})
	if err != nil {
		panic(err)
	}

	db := dynamo.New(sess)

	// テーブル作成をする為に、一度テーブルを削除します
	db.Table("UserTable").DeleteTable().Run()

	// テーブル作成
	err = db.CreateTable("UserTable", User{}).Run()
	if err != nil {
		panic(err)
	}
	// テーブルの指定
	table := db.Table("UserTable")

	// User構造体をuser変数に定義
	var user User

	// DBにPutします
	err = table.Put(&User{UserID: "1234", Name: "太郎", Age: 20}).Run()
	if err != nil {
		panic(err)
	}

	// DBからGetします
	err = table.Get("UserID", "1234").Range("Name", dynamo.Equal, "太郎").One(&user)
	if err != nil {
		panic(err)
	}
	fmt.Printf("GetDB%+v\n", user)

	// DBのデータをUpdateします
	text := "新しいtextです"
	err = table.Update("UserID", "1234").Range("Name", "太郎").Set("Text", text).Value(&user)
	if err != nil {
		panic(err)
	}
	fmt.Printf("UpdateDB%+v\n", user)

	// DBのデータをDeleteします
	err = table.Delete("UserID", "1").Range("Name", "Test1").Run()
	if err != nil {
		panic(err)
	}

	// Delete出来ているか確認
	err = table.Get("UserID", "1").Range("Name", dynamo.Equal, "Test1").One(&user)
	if err != nil {
		// Delete出来ていれば、dynamo: no item found のエラーとなる
		fmt.Println("getError:", err)
	}
}

解説

簡単に解説していきます。

type User struct {
	UserID string `dynamo:"UserID,hash"`
	Name   string `dynamo:"Name,range"`
	Age    int    `dynamo:"Age"`
	Text   string `dynamo:"Text"`
}

ここで構造体を定義しています。
dynamoタグをつける事でdynamoテーブルと構造体をうまくマッピングしてくれます。
hashとつけるとハッシュキーに、rangeとつけるとレンジキーになります。

// 本来はenvから取得した方が良い
const AWS_REGION = "ap-northeast-1"
const DYNAMO_ENDPOINT = "http://localhost:8000"

func main() {
	// クライアントの設定
	sess, err := session.NewSession(&aws.Config{
		Region:      aws.String(AWS_REGION),
		Endpoint:    aws.String(DYNAMO_ENDPOINT),
		Credentials: credentials.NewStaticCredentials("dummy", "dummy", "dummy"),
	})
	if err != nil {
		panic(err)
	}

	db := dynamo.New(sess)

コメントにも書いてある通り、リージョンとかは.envから呼び出すなどした方が良いのですが、こちらの方がわかりやすいかと思い、このような記載としています。
os.Getenvなど使われる事をお勧めします。

	// テーブル作成をする為に、一度テーブルを削除します
	db.Table("UserTable").DeleteTable().Run()

	// テーブル作成
	err = db.CreateTable("UserTable", User{}).Run()
	if err != nil {
		panic(err)
	}
	// テーブルの指定
	table := db.Table("UserTable")

	// User構造体をuser変数に定義
	var user User

この辺りで、テーブルの指定など行っています。
CreateTableする為に、あえて一度テーブル削除してます。

	// DBにPutします
	err = table.Put(&User{UserID: "1234", Name: "太郎", Age: 20}).Run()
	if err != nil {
		panic(err)
	}

	// DBからGetします
	err = table.Get("UserID", "1234").Range("Name", dynamo.Equal, "太郎").One(&user)
	if err != nil {
		panic(err)
	}
	fmt.Printf("GetDB%+v\n", user)

	// DBのデータをUpdateします
	text := "新しいtextです"
	err = table.Update("UserID", "1234").Range("Name", "太郎").Set("Text", text).Value(&user)
	if err != nil {
		panic(err)
	}
	fmt.Printf("UpdateDB%+v\n", user)

	// DBのデータをDeleteします
	err = table.Delete("UserID", "1").Range("Name", "Test1").Run()
	if err != nil {
		panic(err)
	}

	// Delete出来ているか確認
	err = table.Get("UserID", "1").Range("Name", dynamo.Equal, "Test1").One(&user)
	if err != nil {
		// Delete出来ていれば、dynamo: no item found のエラーとなる
		fmt.Println("getError:", err)
	}

DynamoDB LocalでCRUDしてみました。
レンジキーが無い場合は、ハッシュキーだけの指定で大丈夫です。
Deleteして、本当に削除出来ているか確認する為に、もう一度Getしてます。(ここではエラーになりますが、想定通りです)

結果

コマンド

docker-compose up -d
go run main.go

出力結果

GetDB{UserID:1234 Name:太郎 Age:20 Text:}
UpdateDB{UserID:1234 Name:太郎 Age:20 Text:新しいtextです}
getError: dynamo: no item found

こうなっていれば成功です。

さいごに

  • DynamoDB Local思ったより簡単に使えますね。
  • 普通のDynamoDBを練習で使うと料金が意外と高くつくので、練習にはDynamoDB Localを使いましょう。

参考

Discussion