Go(guregu)+lambda+dynamoDBでデータのやりとりをしよう

## はじめに
この記事では、Go（guregu）を用いてLambdaを介し、DynamoDBとのデータのやりとりを紹介します。

## lambdaを動かしてみよう
2023/12/31にLambdaのGoランタイムがサポート終了となりますが、buildしてLambdaへ渡すため、ランタイムは必要ありません。

まずは簡単なコードから実行してみましょう。任意のディレクトリで以下のコマンドを実行して、プロジェクトを作成します。

まずは簡単なコードから実行していきましょう。
任意のディレクトリで
```sh
$ mkdir go-lambda-test
$ cd go-lambda-test
$ go mod init test
```
上から順に実行し、プロジェクトを作成していきます。
ディレクトリ直下にmain.goを作成し、以下のコードを記述します。
```main.go
package main

import (
	"context"
	"github.com/aws/aws-lambda-go/lambda"
)

// ハンドラ関数を定義
func handler() (string, error) {
	return "Hello, lambda", nil
}

func main() {
	// Lambdaのハンドラを起動
	lambda.Start(handler)
}
```
以上記述できたらbuildしてzipファイルへと変換します。
```
$ GOOS=linux GOARCH=arm64 go build -o bootstrap main.go
$ zip test.zip bootstrap
```
また、実行ファイル名はbootstrapにするという命名規則がありますので、守るようにしてください。Lambdaのコンソールから以下の設定で関数を作成します。

ランタイム: Amazon Linux 2023
アーキテクチャ: arm64
zipファイルをアップロードし、テストを行い成功すれば
```
"Hello, lambda"
```
が返ってくると思います。

## DynamoDB
次に、DynamoDBを操作してみましょう。DynamoDBのコンソールからテーブルを作成します。テーブルには`Name`, `Age`, `Hobby`の項目を持つことにしました。

注意点として、LambdaからDynamoDBにアクセスするためにはIAMロールを設定する必要があります。今回は以下のロールを設定しました。

AmazonDynamoDBFullAccess
AWSLambdaDynamoDBExecutionRole
## PUT
```main.go
package main

import (
	"context"
	"fmt"

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

type UserInfo struct {
	Name  string `dynamo:"name"`
	Age   int    `dynamo:"age"`
	Hobby string `dynamo:"hobby"`
}

// ハンドラ関数を定義
func handler(ctx context.Context, userInfo UserInfo) (string, error) {
	db := dynamo.New(session.New(), &aws.Config{
		Region: aws.String("us-east-1"),
	})
	table := db.Table("Test")

	err := table.Put(userInfo).Run()
	if err != nil {
		fmt.Println(err)
		return "Put request failed", err
	}

	return "Put request successed", nil
}

func main() {
	// Lambdaのハンドラを起動
	lambda.Start(handler)
}
```
以上記述できたら先ほどと同じように、buildしてzipファイルへと変換します。
```
$ GOOS=linux GOARCH=arm64 go build -o bootstrap main.go
$ zip test.zip bootstrap
```
テストのイベントJSONを以下のように記述しテストを行います。
```json
{
  "name": "Shinji",
  "age": 16,
  "hobby": "Eva"
}
```
このように記述しテストを行うと
```
"Put request successed"
```
が返り、DynamoDBのテーブル内に書き込まれていることが確認できます。

## GET
```main.go
package main

import (
	"context"
	"fmt"

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

type UserInfo struct {
	Name  string `dynamo:"name"`
	Age   int    `dynamo:"age"`
	Hobby string `dynamo:"hobby"`
}

type UserName struct {
	Name string `dynamo:"name"`
}

// ハンドラ関数を定義
func handler(ctx context.Context, userName UserName) ([]UserInfo, error) {
	db := dynamo.New(session.New(), &aws.Config{
		Region: aws.String("us-east-1"),
	})
	table := db.Table("Test")
	var result []UserInfo

	err := table.Get("name", userName.Name).All(&result)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	return result, nil
}

func main() {
	// Lambdaのハンドラを起動
	lambda.Start(handler)
}
```
テストのイベントJSONを
```json
{
  "name": "Shinji"
}
```
こちらを渡します。
すると
```
[
  {
    "Name": "Shinji",
    "Age": 16,
    "Hobby": "Eva"
  }
]
```
データの取得に成功しました。

Update,Deleteも似たような記述で可能なので、やってみたい方はgureguの作者様が記事を書いてるので参考にしてみてください。

## まとめ
少し興味があり、手を出してみましたがgureguを利用した所感としてはRDBでいうところのORMに近しいと思いました。
興味があればぜひ記事を参考に利用してみてください。
APIGateWayからリクエストを受け取る方式も気が向けば記事にしようと思います。
記事内に間違いなどございましたら教えていただけると幸いです。

### 追記
APIGateWayを介す場合SDKで書いた方が簡単そうですね。

### 参考
guregu [気楽にDynamoDBを使おう] https://qiita.com/guregu/items/2e9ac305791935b86f5d
[Go-lambda] https://pkg.go.dev/github.com/aws/aws-lambda-go/lambda