30分で Slack AppとAWS Lambda(for ruby)を作成して連携させる

本エントリは [iCARE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/icare) の19日目の記事です。

## はじめに
今回作成する機能は
・Slack Appへメンションをつけてメッセージを送信
・Slack Appが自分へメンションを付けて同じ内容のメッセージを返してくる
です。
今回はSlack AppとAWS Lambda(for ruby)の連携方法がメインのためLambdaへ実装する処理自体は簡単なものにしています。
Lambda内のプログラムを修正することで色々な機能が作れると思うので参考になれば幸いです。

## 作成していく手順

- Slack Appの作成
- AWS Lambda(for ruby)関数の作成
- API Gatewayの作成
- Slack AppでAPIの認証とEventの設定

では作っていきます。

## Slack Appの作成

以下のURLからSlackへログインします。
アプリを作成したいワークスペースのアカウントでログインしてください。

```
https://slack.com/signin
```

続いて以下のURLへアクセスします。

```
https://api.slack.com/apps
```

下のような画面が表示されるので[Create New App]をクリックします。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/977511c8-1f14-e54b-ddb2-751b86eb6345.jpeg)

作成したいSlackアプリの名前を[App Name]へ入力し対象のワークスペースを選択して[Create App]をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/748a964c-1d9f-563a-e3c6-ff66aba92fd7.jpeg" width=50%>

作成したアプリへ権限を追加していきます。
[Basic Information] - [Add features and functionality]の[Permissions]をクリックします。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/59086b0b-24d7-6e9b-c831-e5d7c72b3a47.jpeg)

[Scopes]の項目にある[Add an OAuth Scope]をクリックします。
![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/7d0f8c75-eaf8-6d73-9913-8ef95d7d2156.jpeg)

今回は「Slack appへメンションをつけたメッセージを読み取り、そのまま返す」だけなので
[app_mentions:read]、[chat:write]の2つの権限を付与します。
![005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/d136970c-7e70-2cf1-2e80-84d3e0be950e.jpeg)

Permissionについては[OAuth & Permissions]の項目からも遷移でき、後から変更も可能です。
![006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/71935257-7b37-3216-d219-6cf7b5931812.jpeg)

Slackのワークスペースにinstallしていきます。
[OAuth & Permissions] - [Install to Workspace]をクリックします。
![007.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/c0623e10-acde-1fcd-f222-fa8ad304656b.jpeg)

Slackのワークスペースへinstallするための確認画面が表示されるので[許可する]をクリックします。
![008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/640092ac-6eac-e6fc-715a-f82e2135fb94.jpeg)

これでワークスペースでSlack Appを使用することができます。
次に[OAuth & Permissions]の画面へ遷移するので表示されている[Bot User OAuth Access Token]をコピーして残しておきます。
LambdaからSlack App経由でメッセージを送信するために使用します。
![009のコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/ba5a3510-d864-6dbd-8438-8cae1b977a1f.jpeg)

## AWS Lambda(for ruby)関数の作成
続いてAWS Lambda関数を作成していきます。
AWS Console画面よりLambdaのところへ遷移します。
[関数の作成]をクリックします。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/2edb8c1b-6dbf-5610-386a-f72fa0fb8507.jpeg)

今回は[一から作成]のまま作成していきます。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/09078c47-83f4-e699-871b-534a2b2b6603.jpeg)

[関数名]、[ランタイム]、[アクセス権限]を設定します。
[ランタイム]はRuby2.5を指定してください。(2.5でしか動作確認していないので2.7で動作するかは分かりません)
[アクセス権限]は[基本的なLambdaアクセス権限で新しいロールを作成]にしました。
既存のロールを使う場合は[既存のロールを使用する]から選択してください。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/3e666407-3161-38dc-a80d-f0d81cf796b4.jpeg)

[詳細設定]部分は特に設定していないのでこのまま[関数の作成]をクリックします。
![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/1ebb6ce1-6ee0-3522-7874-3fc455e0d0c2.jpeg)

下のような `lambda_function.rb` が作成されます。
![005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/1672ad51-640a-26e6-3c20-ec344bfcce84.jpeg)

この `lambda_function.rb` にある lambda_handler関数が実際にLambdaを呼び出された時に実行される関数です。
今回はこの処理の中にslackからイベントが通知されるのでそのparameterを解析して該当のchannelへ返すという処理を実装します。
処理は↓で公開しています。
https://github.com/Nobuo-Hirai/parrot-for-Lambda

Lambdaへのdeployは以下の手順でおこないます。

```
git clone git@github.com:Nobuo-Hirai/parrot-for-Lambda.git

## bundle install
## gemもLambdaのアプリケーション内に含める必要があるので vendor/bundle 配下へinsallしてください。
bundle config set --local path 'vendor/bundle'
bundle install

## zip file作成
zip -r parrot-for-Lambda.zip vendor Lambda_function.rb

```

zipファイルを作成したらLambdaの[zipファイルをアップロード]よりアップロードします。
(zipファイルのサイズが10MBを超えたらS3経由になります)
![006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/8450d355-d25e-1551-ebb9-7bfee3ffe52a.jpeg)

次にLambda functionで使用する環境変数を設定します。
設定方法は下の環境変数の[編集]より設定します。
![007.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/99e9bfbb-97ec-88f5-f3e4-671c8c4d0cb6.jpeg)

使用する環境変数は以下の3つを設定します。

| キー | 値 |
|---|---|
|api_app_id |Slackのapi_app_id (SlackのAppページに表示されているApp ID)|
|channel_id |呼び出し元のSlack channel id。対象のchannel以外は実行を許可しないようにする。(channel idの確認方法は該当のchannelをアプリで選択して、右クリックでリンクをコピーします。それをブラウザへ貼り付け、/archives/以降がidです)|
|slack_token|Slackのaccess token(Bot User OAuth Access Token)|

channel_idの確認方法が分かりにくいのでスクショを添付しておきます。
archives/以降の最後の部分です。
![008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/d0395e1f-3d2a-041a-c8d6-556b04d87258.jpeg)

設定後は以下のようになっていると思います。
![009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/ca335c34-890c-40dc-a19d-82bc4461c7a4.jpeg)

## API Gatewayの作成
続いてSlackとLambdaを繋ぐAPI Gatewayを作成します。
AWS API Gatewayへ遷移して[APIを作成]をクリックします。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/0f01394d-629f-9d29-974a-a062313cc979.jpeg)

[新しいAPI]を選択し、[API名]へ任意の名称を入力し[APIの作成]をクリックします。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/92bc7ba0-b0ff-732b-0821-4c67b1067c7b.jpeg)

[アクション] - [メソッドの作成]をクリックします。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/13bcfe2d-20f8-7731-227e-824387201e6e.jpeg)

続いて[/ (スラッシュ)]部分をクリックして[POST]メソッドを選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/d0ac144c-d0cc-3de3-0c7d-d70a6bce866a.jpeg" width=50%>

メソッドの設定として以下を設定し[保存]をクリックします。

```
統合タイプ：Lambda関数
Lambdaプロキシ統合の使用：チェックあり
Lambdaのリージョン：該当のLambda functionのリージョンを指定
Lambda関数：作成したLambda関数の名前を入力
デフォルトタイムアウトの使用：チェックあり
```
![005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/964784cc-2b51-fa75-39df-589655dec709.jpeg)

Lambda関数への権限追加を確認する画面が表示されるので[OK]をクリックします。
![006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/cb588489-58f7-2362-668a-9e3df1013dc6.jpeg)

以下の画面が表示されるので[アクション]より[APIのデプロイ]を選択します。
![008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/9e9b8b82-5178-d2e0-34bf-6de38d36e21c.jpeg)

ステージ名を入力して[デプロイ]をクリックします。(これがエンドポイントの一番最後の文字列になります)
![009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/355cd3fc-2a43-bd6a-2e3d-50887899dc1a.jpeg)
以上でAPI GatewayとLambda関数の紐付けが完了し、APIのエンドポイントが作成されました。
[画面のURLの呼び出し]部分に表示されているURLがエンドポイントになるのでコピーして保存しておいて下さい。
![010のコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/2a160a7d-5056-469b-9f56-13cc2e67f309.jpeg)

## Slack AppでAPIの認証とEventの設定
続いてSlack Appで作成したAPIエンドポイントの認証をおこないSlack AppへのメンションがあればAPIをcallするという設定が必要なためその対応を進めていきます。

Slack Appの画面へ戻り[Event Subscriptions]を選択します。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/a04e436c-2d48-a421-4ac3-351fcd574f83.jpeg)

最初は[OFF]になっているEnable Eventsを[ON]へ変更します。
その次にRequest URLへ先ほどのAPIのエンドポイントのURLを入力しVerifiedとなればOKです。
ここではSlackからAPIエンドポイントへ疎通確認をおこなっています。
具体的には{ challenge: xxxxx }というパラメータが送信されるのでそのchallengeパラメータをそのまま返す必要があります。
これはlambaの処理で

```
# slackのEvent APIの認証用
  if event["body"].present? && JSON.parse(event["body"])["challenge"].present?
    return { statusCode: 200, body: JSON.parse(event["body"])["challenge"] }
  end
```
という箇所で実装しています。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/96595a9b-2e6d-2459-7737-1debec7b273b.jpeg)

次にSlack AppへのメンションがあればAPIをcallするという機能を追加するため[Subscribe to bot events]の[Add Bot User Event]より[app_mention]を追加し[Save Changes]をクリックします。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/278f2a51-6a11-3dbb-ff4d-5d595d17a36d.jpeg)

以上で全ての実装は終わったので実際にSlack Appを呼び出してみたいと思います！！
![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67654/e10238dc-4cc8-62c4-4956-9e85cc7fa76f.jpeg)

` @parrot [メッセージ] `
を送信すると同じメッセージを返してきました！成功しましたね！
30分、、はちょっと言いすぎたかもしれないですが簡単にSlack AppとLambdaは連携できるので是非試してみて下さい！
今回は処理自体は簡単な内容でしたがlambda function内の実装を変えることで色々できて楽しそうです！

## 
## 最後に
iCAREでは[Tech Blog](https://dev.icare.jpn.com/dev_cat/)も毎月投稿されているので是非みてください〜！
また[Meet Up](https://icare.connpass.com/)も開催しているのでご興味ある方はお気軽にご参加ください！