slack interactive messageをaws api Gatewayで受け取り、Lambdaでパースする。

# はじめに
インターンで作成した受付アプリの中でSlackのinteractive messageを利用した際に少し躓いたため、共有します。

- Slackにメッセージ送信(Webhook)->ボタン押下(Slack)->メッセージ書き換え
- 機能自体はawsおよびSlackについて無知な状態から6日間ほどで作成

# API Gateway作成
一般的なやり方でAPI Gatewayを作成し、POSTメソッドを定義します。
![スクリーンショット 2019-07-26 11.42.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/d63551af-7e50-f3f8-2ca4-c1310ecb1ba2.png)
普通です。

正直試行錯誤していた時の記憶が曖昧なのでもしかしたら設定を変えている部分があるかもしれません。

なかなかLambdaでうまく受け取れなかったためこの辺りを参照しましたが、結局Lambdaでデコードおよびパースしたため効いていないように思います。
https://qiita.com/durosasaki/items/83af014aa85a0448770e

デプロイしてエンドポイントを発行します。
発行したエンドポイントのURLをSlack Appの**Interactive Components**のRequest URLの部分に書き込みます。

![スクリーンショット 2019-07-26 11.40.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/07d40ad9-8960-024d-69e6-fd5174e2a90f.png)

これで一先ずはSlackからAPI Gateway+Lambdaへの流れができたことになります。

# ログを見ることの大切さ
私が躓いたのはここです。デバッグをするにあたってSlackからそもそもリクエストが飛んできていないのか、などと疑ってしまいました。ログを見れば良かったんだと気づくまでに超絶時間がかかり、時間を溶かしてしまったのは内緒で。

さて肝心のどうやってログを見るのかということですが、Lambdaに紐づいているロールに**Amazon CloudWatch**と**Amazon CloudWatch Logs**を含めます。Amazon CloudWatchのみで十分だと思っていましたがログが書き込まれなかったためおそらく両方必要です。
![スクリーンショット 2019-07-26 11.48.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/4c9cf7c1-89a5-8c35-307a-4badddb2e891.png)

さらに、関数コード内に以下を記入します。

```python
import subprocess
import logging

# ログ設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# イベントハンドラ
def lambda_handler(event, context):
    logging.info(json.dumps(event))
    # 以下略
```

これでAmazon CloudWatchのリソース内のログ部分から、どんなリクエストが飛んできたのかを見ることが可能です。jsonでdumpしてあげると見やすいので強くお勧めします。
![スクリーンショット 2019-07-26 11.53.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205918/75049181-25a6-78ce-630c-fb5db77d9782.png)

ここで確認すると、Slackからのリクエストはしっかりと届いていました。どうやら自分のパースがうまく出来ていなかったせいでSlack上でボタンを押しても次のアクションに繋がらなかったようです。

# Slackからのリクエストのパース

```json-doc
{
    "headers": {
        "Accept": "application/json,*/*",
        "Accept-Encoding": "gzip,deflate",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "US",
        "Content-Type": "application/x-www-form-urlencoded",
...略
    },
    "querystring": {
        "payload": "{slackからのメッセージ本文がx-www-form-urlencodedされたもの}"},
...略
}

```

Slackからのリクエストの中身を見てみると`"Content-Type": "application/x-www-form-urlencoded"`で取得できていることがわかりました。つまり、Lambdaでは`event["querystring"]["payload"]`をデコードしてあげればjsonでパース可能な形になるわけです。(これに気づくまでに地球が３周しました。)

というわけで以下Lambda上のパース部分のみ取り出して載せておきます。

```python
def lambda_handler(event, context):
    logging.info(json.dumps(event))
    # print(event) #デバッグ用
    #urlencodedされているためデコードする
    response = json.loads(unquote(event['querystring']['payload']))
    print(json.dumps(response))
    print(response['response_url'])
    # 返信用URL
    response_url = response['response_url']
```

# まとめ
- PaaSでログ見る方法ってシンプルに思えて結構入り組んでいるように感じました。慣れればどこ見ればいいかすぐに分かるはずですが初心者にはキツかった(涙)
- API Gateway側でjsonにdumpしてLambdaに渡す処理の記事読んだけど全く理解できずに断念したので、LambdaのPythonでdecodeできてよかったです。これができなかったら存続の危機だった。
- SlackのAPIの仕様が新しくなって過去の文献があまり役に立たなかったりするのでお気をつけください。
- Slack clientのZipをアップロードをして実装している記事もありましたが面倒なのでお勧めしません。今動くのか？