2021-11-27

AWSLambda(Golang)×DynamoDBのローカル開発環境を整える

blogimg

# 目的

AWS LambdaでバックエンドAPIを構築しているとき、関数の挙動を確認したいときは都度devにデプロイしていました。流石にローカルでの開発環境を整えたいと思ったのですがGoでの使い方の情報が少なかったので個人メモとしてまとめてみました。

今回はAPI GatewayがトリガーのLambda関数になります。

serverless invoke local -f <function>で十分らしいです

# 全体の流れ

以下のJavascript filesのところを今回はGolangにしてやってみます。

引用: https://qiita.com/noralife/items/e36621ddd0e5b8ff4447#%E6%A7%8B%E6%88%90

大まかな流れは以下です。

1. DynamoDB Localをインストール&セットアップ

2. Serverless offlineをインストール &セットアップ

# DynamoDB Localをインストール&セットアップ

## パッケージインストール

$ npm install --save-dev serverless-dynamodb-local

## serverless.ymlにプラグインを追記

```serverless.yml

plugins: 
 - serverless-dynamodb-local

```

## JDKがなければここでインストール

dynamodb-localのためにはJavaが必要でしたので、ローカルpcにJavaを入れていない方はインストールします。

インストールの仕方は、mac osだと、以下が参考になります。

https://qiita.com/suke_masa/items/f9af0fb84ad9447ae961

## dynamo db localをインストール

serverless.ymlのあるディレクトリにて、

```sh
$ sls dynamodb install
```

## カスタム定義

```serverless.yml
custom:
  dynamodb:
    stages:
     - dev
    start:
     port: 8000
     inMemory: true
     migrate: true
     seed: true
    seed:
     development:
      sources:
       - table: テーブル名
```

この状態で、

```sh
sls dynamodb start
```

でdynamodbがローカルで立ち上がります。

http://localhost:8000/shell

にアクセスすると管理画面に移れる。

シェル例

```
var params = {
  TableName: 'pr_enqueteform_dev',
};
dynamodb.scan(params, function(err, data) {
  if (err) ppJson(err);
  else ppJson(data);
});
```

# Serverless offlineをインストール &セットアップ

次にローカルでapi gatewayを試すためにServerless offlineをインストールしていきます。

## パッケージインストール

```sh
$ npm install --save-dev serverless-offline
```

## serverless.ymlにプラグインを追加

```serverless.yml
plugins: 
 - serverless-dynamodb-local
 - serverless-offline ### 追記
```

## カスタム定義

```serverless.yml
custom:
 serverless-offline:
  useDocker: true
```

この状態で

```sh
$ npx sls offline
```

でローカルで起動できます。

※Makefileにて、

```sh
$ make local-test
```

を打つことでビルド〜offline起動までやってくれるようにしています。

例:

```sh
$ npx sls offline
Serverless: Deprecation warning: CLI options definitions were upgraded with <中略>
  ┌───────────────────────────────────────────────────────────────────────────────────────┐
  │                                            │
  │  POST | http://localhost:3000/dev/submit                       │
  │  POST | http://localhost:3000/2015-03-31/functions/EnqueteformReceiver/invocations  │
  │                                            │
  └───────────────────────────────────────────────────────────────────────────────────────┘

offline: [HTTP] server ready: http://localhost:3000 🚀
offline:
offline: Enter "rp" to replay the last request

offline: POST /dev/submit (λ: EnqueteformReceiver)
```

上記みたいな感じになっていたら立ち上がっています🎉

# offlineとdynamodb-localを疎通させる

localでofflineを使ってlambda apiを叩いてログを出力してみると、

handlerのeventsの中の、

events.APIGatewayProxyRequest.RequestContext.APIID

"offlineContext_apiId" となっていました。

そこで、この部分で判断して、localのdynamodbクライアントを生成するか本番用のdynamodbクライアントを生成するかを条件分岐させることにします。

localのdynamodbクライアントの生成方法は以下でやります。

```go
func (c *DynamoDBClient) OfflineDynamoDBClient(region string, tableName string) *DynamoDBClient {
	sess := session.Must(session.NewSession())
	config := aws.Config{
		Region: aws.String(region),
		Endpoint: aws.String("http://host.docker.internal:8000"),
		DisableSSL: aws.Bool(true),
		Credentials: credentials.NewStaticCredentials("dummy", "dummy", "dummy"),
	}

	dynamodbClient := DynamoDBClient{
		tableName: tableName,
		dynamo:  dynamodb.New(sess, &config),
	}

	return &dynamodbClient
}
```

※もっとよい判定方法がありそうな感じです。

# 試してみる

ローカルでコードを編集した後、一度ビルドしなければローカルの方にも反映されませんので、

```sh
$ make clean
$ make build
$ npx sls offline
```

とします。

## curlで疎通してみる

sls offlineしたターミナルとは別のタブにて、

```sh
curl http://localhost:3000/dev/submit -X POST -H "Content-Type: application/json" -d '{"category":"hogecategory","email":"sample@gmail.com","address":"東京都", "hoge":{"id":"1001","text":"hogehoge"}}'
```

sls offlineしたターミナルのタブにてログが出てくる。

```sh
START RequestId: d09*7296d-***-1c72-545b-5**c58d99034 Version: $LATEST

<中略>

END RequestId: d09729?6d-b4e2-1c72-5*45b-5e**ec58d99034
REPORT RequestId: d09?7296d-*b4e2-1c72-545b-5c5*d99034	Init Duration: 189.68 ms	Duration: 5513.25 ms	Billed Duration: 5514 ms	Memory Size: 3008 MB	Max Memory Used: 34 MB
```

実際にローカルのdynamoDBにデータを挿入する関数であれば、

http://localhost:8000/shell

をみてみると挿入されていることが確認できます!

# 参考

Serverless Framework での AWS Lambda + Go ローカル開発事情

Serverless アプリケーションをローカルで開発する

serverless framework + TypeScript +DynamoDB のローカル環境

Go で DynamoDB Local を使った時にいろいろハマったのでメモ

example