API Gateway&Lambda&DynamoDBデプロイエラー集

# エラー集
SlackBoltを使用して作成したSlackBotを、API GatewayとLambdaでデプロイした際に、かなりエラーと出会いました。今後開発される方(と自分)の参考になればと思い、開発中に出会ったエラー集まとめました。

## Slack上でAPIを登録する際にURLが正しくないとエラーが起きる

<img width="1177" alt="Slack_API__Applications___naberina_project_Slack.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/8d563864-4c17-6b9c-ecdc-5bb06cdce610.png">


```javascript:index.js
var body = JSON.parse(event.body);
if (body.type == 'url_verification') {
    const res = { challenge: body.challenge }
    return {statusCode: 200, body: JSON.stringify(res) }
  }

```

[SlackAPIリファレンス](https://api.slack.com/events-api)


## APIを叩いた後にエラーが起きる
`"errorMessage": "No token and no authorize options provided. Apps used in one workspace should be initialized with a token. Apps used in many workspaces should be initialized with a authorize.",`

<img width="1501" alt="Lambda_Management_Console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/86e3092c-4067-cc8d-a354-d3b4ea25c984.png">


## APIGatewayのログをcloud watchに出力する際のエラー
![API_Gateway.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/bf3bafb6-8854-f76e-47f0-48bc8771bc9e.png)

解決策はこれっぽいぞ
[API Gateway API をトラブルシューティングするために CloudWatch ログを有効化するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/api-gateway-cloudwatch-logs/)


## 無限ループする
人気者みたいに通知止まらない。
秒間２通くらいメッセージ飛んでくる...
<img width="191" alt="Slack_____なべりな___naberina_project___37_個の新しいアイテム.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/171a4df1-dd1d-2271-18e5-212421e4f523.png">
原因は凡ミスで、SlackAPIのInteractive Componentsの設定でメッセージが投稿されたらLambdaをキックするイベントを登録していたため、メッセージが投稿されるたびにlambdaが叩かれめちゃくちゃメッセージが届く仕様になってしまっていた。。


## API GatewayからLambdaを叩く際のエラー
`400_client_error` でエラーが起きている

![CloudWatch_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/9cb89c05-9128-837b-1321-c88e582f5a23.png)

パラメータを整形する方法は2つある。
1. API Gatewayの統合リクエストでマッピングテンプレートを作成する
https://maitakeramen.hatenablog.com/entry/2019/02/22/105438
2. API Gatewayの統合リクエストでLambda プロキシ統合の使用にチェックする
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html

今回は2の方法でエラーを解消。


##  APIGatewayから送信された値を整形する&パラメータデコードする
```:CloudWatchLog
(54b5c973-9a0e-4109-8082-6dffa303f3d8) Method request body before transformations: payload=%7B%22type%22%3A%22message_action%22%2C%22token~~~~~~`block_id%22%3A%221o [TRUNCATED]
```

どうやらパラメータの値が整っていないらしい。
ログから確認すると、パラメータに不要な`payload='` がついていたり、オブジェクトではなかったりでパラメータが取り出せない問題がありました。

ここまでくるのに、めちゃくちゃ時間が掛かりました。
何と言っても、LambdaとAPIGatewayのデバッグに時間かかりすぎて...

**パラメータを整えて、オブジェクトに変換します**

```javascript:index.js
  const body_split = event.body.split('payload=').join('');
  const event_body = decodeURIComponent(body_split);
  var obj = JSON.parse(event_body);
```

**特定の文字列を削除する方法**
正規表現を使わない場合は、以下のようにsplitとjoinを組み合わせる方法があります。
splitを実行してaで区切った配列に変換し、joinで配列を全て結合することにより、区切り文字のaが削除されるという方法です。

```javascript:参考例
var str = 'abcabc';
console.log(str.split('a').join('')); // "bcbc"

-----------------
// jsonぽい形のデータをオブジェクト化する
var date ='{"ts":+"1573443403.004500",+"title":+"テストテスト",+"channel":+"QWERTY~~"}'
var body_split = date.split('+').join('');
var date = (new Function("return " + body_split))();
console.log(date);
```
[
JSONらしき文字列をオブジェクトに変換するJavaScript](https://hamalog.tumblr.com/post/4047826621/json%E3%82%89%E3%81%97%E3%81%8D%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8Bjavascript)

## Lambda実行時刻が、UTCになってしまう問題
Lambdaコンソール上の環境変数の設定をしよう。
`process.env.TZ = "Asia/Tokyo";`
[LambdaのNode.js v8.10でタイムゾーンを指定してもDateがUTCになる問題](https://qiita.com/r_plus/items/96678b432a1f4fdfc318)

## DynamoDBに空欄は保存できないエラー
DynamoDBに空欄は保存できないため、ValidationExceptionエラーがでてしまう。
`ValidationException: ExpressionAttributeValues contains invalid value: One or more parameter values were invalid: An AttributeValue may not contain an empty string for key`
以下のサイトを参考にして、空欄許可のオプションを追加することで、nullとしてDBに保存される。
[DynamoDB は空の値を登録できないけど DynamoDB document client のコンストラクタにオプションを渡すだけで空の値を NULL 型には変換できるよ？](https://qiita.com/kotarella1110/items/070c4544c7d836b82a3a)

## まとめ
1つのエラーを解消したと思ったら、割とすぐに次のエラーに出会って心折れそうになったので、
😉とか😘とかでエラーメッセージをポップにしてみました。

今回のエラーをメモ程度にまとめておいたことで、割と自分に救われました。
誰かの何かの参考になれば幸いです！

もし何か修正箇所があれば、教えていただけると助かります。

#### 今回の実装で参考にしたサイト
- DynamoDB
 - [DynamoDBのテーブル作成](https://qiita.com/blackcat5016/items/e41f7fb8b6b7a0c9b90b)
 - [AWS LambdaからDynamo DBにデータを追加する](http://kakts-tec.hatenablog.com/entry/2017/06/25/170127)
 - [AWS SDKでDynamoDBを操作(挿入, 取得, 更新, 削除)](https://www.wakuwakubank.com/posts/670-nodejs-dynamodb/)

- Lambda
 - [LambdaのNode.js v8.10でタイムゾーンを指定してもDateがUTCになる問題](https://qiita.com/r_plus/items/96678b432a1f4fdfc318)