AWS LambdaでLINE⇒Slackにメッセージ連携したメモ

Lambda関数でLINEのメッセージを受信してSlackに通知する手順をまとめておきます。
自分用メモ。

## 前提
- 開発環境：Cloud9
- OS：Amazon Linux 2023
- Pythonバージョン：3.10

## Slack側準備
### 動作環境作成
自分が管理者権限を持つワークスペースと投稿先のチャンネルを作成しておきます。
改めて説明することは特にない。

### Slackアプリの作成
外部からSlackにアクセスするため、窓口となるアプリを作成します。
[Slack の bot を自作する（AWS Lambda + API Gateway）](https://qiita.com/landwarrior/items/dfac36a1aadac9ab0cd5#slack-app-%E3%82%92%E4%BD%9C%E6%88%90)記載の手順を参考にSlack Appを作成しました。が、今回はLINE⇒Slack連携なのでApp作成後は「Event Subscriptions」の設定は不要です。

### Webhookの追加
App作成後、左メニューから「Incomming Webhooks」を選択して「Activate Incoming Webhooks」をOnにします。
<img width=400 title="slack_webhook.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62668/2d1d109b-f64b-feb7-731b-22db595c186d.png">
同じ画面一番下の「Add New Webhook to Workspace」を選択。
<img width=300 title="slack_webhook2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62668/4e29e073-e448-15ff-3fb8-0d68d4bc8fd3.png">
Appが通知するチャンネルを指定して投稿を許可します。
<img width=300 title="slack_webhook3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62668/d970ffce-0e44-4e6d-a547-ccd2b13cb994.png">
slack apiの画面に戻るとWebhook URLが生成されているので控えておきます。

## AWS側作業
### Lambda関数作成～LINE連携
手順は[LambdaにLine BOTを作ったメモ](https://qiita.com/_saino/items/39134c7bc8757ac776a9)参照。

### Slackに送信するメッセージ作成
Slackは画像やらボタンやらマークダウンやらが使えるので、せっかくなら多少リッチな見た目にしたいですね。しかしPOST通信のbodyに何を渡せば思ったような見た目になるのかわからない…となったので[Block Kit Builder](https://app.slack.com/block-kit-builder/)を使ってみました。

<img width=600 title="slack_builder.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62668/29ee2639-7d4c-577e-2569-b1b2ec6211d6.png">

| # | 画面要素の概要 |
|--:|:-----------------------------|
|1|Slackに投稿されたときのメッセージの見た目。<br>セクションの並び順変更や削除もここを操作する。|
|2|セクションやボタン、テキストボックス等のブロックを選んで追加できる。|
|3|テンプレートを読み込む。1から並べるのは面倒なので便利。|
|4|メッセージの本体となるJSON。<br>テキストボックスになっているので文章を入れてみることも可能。|

### Lambda関数実装
お試しのつもりなので何も考えずにWebhookのURLにリクエストを送る実装にしました。Lambda環境変数「slack」に[webhookの追加](#webhookの追加)で控えておいたWebhook URLを登録しています。
環境変数周りの話も[LambdaにLine BOTを作ったメモ](https://qiita.com/_saino/items/39134c7bc8757ac776a9)でまとめたので省略。
 
```python:app.py
import json
import os
import urllib.request
import logging

# Slack Webhook URL
SLACK_URL = os.environ['slack']
# Logging Initialize
log = logging.getLogger()
log.setLevel(os.environ['logLevel'])

def lambda_handler(event, context):
    log.debug(event)
    
    for message_event in json.loads(event['body'])['events']:
        headers = {
            'Content-Type': 'application/json; charset=utf-8',
        }
        body = {
            "blocks": [{
                # ここにBlock Kit Builderで作ったPayloadが入る
                # どこかのtextにmessage_event['message']['text']を入れておく
            }]
        }
        log.debug(body)

        req = urllib.request.Request(SLACK_URL, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
        with urllib.request.urlopen(req) as res:
            log.info(res.read().decode("utf-8"))

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "success",
        }),
    }
```
以下を参考に実装しているんですが、bodyの構造に関するドキュメントが見つけられてないので[Slackに送信するメッセージ作成](#slackに送信するメッセージ作成)で作ったblockはattachments以下に入れておきました。[slack apiのDocsのchat.postMessage](https://api.slack.com/methods/chat.postMessage)に近いけど、必須項目とかが違うしなぁ…。
　参考：[Line API × AWS Lambda×Slack Incoming WebhookでLineのメッセージをSlackに自動投稿させる](https://bbb.bit2byte.co.jp/2020/11/10/line-api-aws-lambdaslack-incoming-webhook%e3%81%a7line%e3%81%ae%e3%83%a1%e3%83%83%e3%82%bb%e3%83%bc%e3%82%b8%e3%82%92slack%e3%81%ab%e8%87%aa%e5%8b%95%e6%8a%95%e7%a8%bf%e3%81%95%e3%81%9b%e3%82%8b/)
　⇒'24/4/4：引用の入れ子みたいになってたのがattachments削除すると直ったのでサンプルコードから削除

## テスト
LINEにメッセージを送ってみたらSlackに投稿されるようになった！
下記の引用テキスト「テストだよ」がLINEで送信されたテキストになっています。 
~~bodyにusername入れてみたけど別に動いてないからattachments以下だけでよさそう。~~
　⇒'24/4/4：サンプルコードから削除
![slack_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62668/1cf6fb85-d349-ce33-d2b7-2aa28151f58c.png)
ボタンは今後追加したいという気持ちのハリボテです。

今回はloggingを入れているので動かなかったらCloudWatchで原因確認しつつ、デバッグが終わったらLambdaのコンソールから環境変数を編集してログレベルをINFOにしておく感じにしました。コード直して再デプロイするよりは楽。

## おわりに
メッセージの組み立てがややこしいだけでただのPOSTなので簡単でよかった。次回はこのSlack通知のスレッドでLINEに返信できるか検討しつつ、コードをsdkでキレイにしていければいいなぁという気持ちです。
先人の皆さんに感謝感謝。