【kintone×Webhook】Slack通知ハンズオン

## はじめに
この記事では、kinotneのWebhookを使用して、
kintoneにレコードが登録されたら、Slackに通知する方法を紹介します。

## 全体図
![システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/064f3209-4751-860c-79ca-1897dc064b44.png)


## 必要なもの
- kintoneアカウント
- AWSアカウント
- Slackワークスペース

## kintone開発者ライセンス(※kintoneアカウントをお持ちではない方)
kintone環境をお持ちではない開発者の方は、[kintone 開発者ライセンス（開発環境）](https://developer.cybozu.io/hc/ja/articles/200720464-kintone-%E9%96%8B%E7%99%BA%E8%80%85%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9-%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83-)より環境を取得してください。無料でkintone開発環境を取得することができます。

## カスタマイズ手順
1. kintoneでアプリを作成
1. Slackのカスタムインテグレーションを追加
1. Slack通知させるコードを書く
1. AWS Lambda設定
1. AWS APIGateway設定
1. kintone WebhookにURL登録
1. 動作確認(kintoneに1件データを登録)

### 手順イメージ図
![手順.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/d112b296-6c55-d51b-d557-dc55f3dd7792.png)

## ハンズオン

### 1. kintoneでアプリを作成
まずは、kintoneにアプリを作成しましょう！
今回は試しに、kintoneアプリストアのタイムカードアプリを使ってみます。
何かしらのアプリが登録できればOKです。
![Cursor_と_タイムカード_-_レコードの一覧.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/2f2be76c-61ab-951b-b7b7-7cb12ba992c0.png)


### 2. Slackのカスタムインテグレーションを追加
Slack通知させるためには、通知をしてくれる任意のBotアプリを登録します。
任意のBotアプリは、[Your Apps](https://api.slack.com/apps) から作成できます。

#### BotApp 作成手順
1. `Create New App`から、`From scratch`を選択してAppを作成します。
2. App名をつけ、インストールしたいSlackのワークスペースを選択します。
3. `Add features and functionality` > `Incoming Webhooks` を開きます。
Activate Incoming WebhooksをONにします。
4. `Add features and functionality` > `Bots` を開きます。
Your App’s Presence in Slackを設定します。
EditボタンからDisplay Nameを登録してください。
5. 再度、`Add features and functionality` > `Incoming Webhooks` を開きます。
スクロールした一番下にある`Add New Webhook to Workspace` から通知を飛ばすチャンネルを選択します。

![Slack_API__Applications.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/91578002-c0ac-e53f-17a2-797d93197a1f.png)


`Add features and functionality` > `Incoming Webhooks`のWebhook URL は後ほど使用します。どこかにメモしておくと良いかもしれません。

![webhookurl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/1160ff73-a353-c293-668a-7ed1619e9ea2.png)



<details><summary>📣【解説】Slack通知に必要なパラメータを確認する</summary>

**Slack Incoming WebhookのURL**宛に、**JSONペイロードデータ**(`{"text":"Hello, World!"}`)を渡すと設定したのチャンネルに通知が届きます。

```shell:curlサンプルリクエスト
curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' https://hooks.slack.com/services/~~~~/~~~~
```

JSONペイロードデータは必須項目の`text`の他に、`blocks`や`attachements`が存在します。
詳細はSlackのドキュメントを確認してみてください。
参照: [Reference: Message payloads](https://api.slack.com/reference/messaging/payload)

Slack側の設定をもう少し知りたい方は、こちらの記事もおすすめです。
参照: [slackのIncoming webhookが新しくなっていたのでまとめてみた](https://qiita.com/kshibata101/items/0e13c420080a993c5d16)

</details>

### 3. Slack通知させるコードを書く

適当なディレクトリにアプリを作成します。
```shell
$ mkdir kintone-webhook
$ cd kintone-webhook
```

メインファイルの作成と、今回使用する[Node Slack SDK](https://github.com/slackapi/node-slack-sdk)をインストールします。

```shell
kintone-webhook$ npm init -y
kintone-webhook$ npm i @slack/webhook
kintone-webhook$ touch index.js
```

Slack SDKの[公式ドキュメント](https://slack.dev/node-slack-sdk/webhook)の書き方を参考にコードを書いていきましょう。

```javascript:index.js
const { IncomingWebhook } = require("@slack/webhook");
const url = process.env.SLACK_WEBHOOK_URL;
const kintone_app_url = process.env.KINTONE_APP_URL;

exports.handler = async (event) => {
  "use strict";
  const webhook = new IncomingWebhook(url);
  try {
    let message = `出勤しました！\n 詳細: ${kintone_app_url}show#record=${event.record.レコード番号.value}`;
    await webhook.send({
      attachments: [
        {
          color: "#f2b844",
          text: message,
        },
      ],
    });
  } catch (error) {
    console.error(error);
  }
};
```

AWSのLambdaにアップロードするため、作成したコードをzipファイルにしておきます。

```shell
kintone-webhook$ zip -r slack_notice.zip index.js node_modules/
```
構文: `zip -r [圧縮時のzipファイル名] [圧縮したいフォルダ名]`

<details><summary>📣【解説】コードの詳細を確認しよう</summary>

先程書いたコードのポイントを2つ解説します。

#### 1. Lambda handlerの引数
以下のコードの引数(event)の中身を紹介します。
```js
exports.handler = async (event) => {
```

AWS Lambdaの公式デベロッパーガイドには、以下のように解説されています。
> ランタイムでは、ハンドラーメソッドに 3 つの引数を渡します。最初の引数は、呼び出し元からの情報を含む event オブジェクトです。呼び出し元は、Invoke を呼び出してこの情報を JSON 形式の文字列として渡し、ランタイムはそれをオブジェクトに変換します。AWS のサービスで関数を呼び出す場合、そのイベント構造はサービスによって異なります。
引用：[Node.js の AWS Lambda 関数ハンドラー](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-handler.html)


つまり、第一引数の `event`には呼び出し元であるkintoneのレコード情報のJSON形式の文字列が格納されています。`event.record.~~`でkintoneのレコードデータを取得することができます。

#### 2. Slackにメッセージを送信する
[公式ドキュメント](https://slack.dev/node-slack-sdk/webhook)のSend a notificationを確認すると、`Webhookオブジェクト`に`.send`メソッドを利用してテキストパラメータを渡すとSlackにメッセージを通知することができると記載されています。

```js
const webhook = new IncomingWebhook(url);
:
:
await webhook.send({
  attachments: [
      {
        color: "#f2b844",
        text: message,
      },
   ],
});
```

今回は`text`のみをパラメータに含めていますが、`block`や`attachments`を使用するとボタンや画像などの送信も可能です。
参照: [Reference: Message payloads](https://api.slack.com/reference/messaging/payload)

さらに、[Block Kit Builder](https://app.slack.com/block-kit-builder/T0L1X4QLW#%7B%22blocks%22:%5B%7B%22type%22:%22section%22,%22text%22:%7B%22type%22:%22mrkdwn%22,%22text%22:%22Chew%20choo!%20@scott%20started%20a%20train%20to%20Deli%20Board%20at%2011:30.%20Will%20you%20join?%22%7D%7D,%7B%22type%22:%22actions%22,%22elements%22:%5B%7B%22type%22:%22button%22,%22text%22:%7B%22type%22:%22plain_text%22,%22text%22:%22Yes%22,%22emoji%22:true%7D%7D,%7B%22type%22:%22button%22,%22text%22:%7B%22type%22:%22plain_text%22,%22text%22:%22No%22,%22emoji%22:true%7D%7D%5D%7D%5D%7D)を使用すれば、UI上で簡単にパラメータを設定できます。

</details>

### 4. AWS Lambda設定

#### Lambda関数を作成する

まず、[AWS Management Console](https://aws.amazon.com/jp/console/)にログインします。
次に、検索バーに「Lambda」を入力し、Lambdaのダッシュボードを表示します。

関数の作成ボタンからLambda関数を一から作成します。
![関数_-_Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/b0ce6598-9744-e6fc-a7fe-d113e93ff56d.png)

##### 設定項目
- Lambda関数名をつける
- ランタイム: Node.js 14x
- 他の項目はデフォルト値のまま

関数の作成ができたら、先程zipしたファイルをアップロードします。
![qiita-aws.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/36b22ee2-17ab-ac63-6025-7fab4067605f.png)
コードのアップロードが完了したら、環境変数を設定します。

#### 環境変数設定

コードの下のメニュータブから、①設定 を選択し、 ②環境変数 を表示する。
右側の ③編集 ボタンから環境変数を登録していきます。

![設定タブ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/b708e557-cc3c-aac8-f8c0-c19c4a4c2ca8.png)

2つの環境変数を登録します。

|キー|値|
|:--|:--|
|SLACK_WEBHOOK_URL|コピーしたSlackのWebhookURL|
|KINTONE_APP_URL|kintoneアプリのURL|

ここに登録することで、コード上で `process.env.環境変数キー` で呼び出すことができます。

```javascript:今回のコードでは下記で呼び出している
const url = process.env.SLACK_WEBHOOK_URL;
const kintone_app_url = process.env.KINTONE_APP_URL;
```

### 5. AWS APIGateway設定
Lambdaのトリガー追加からAPIGatewayを登録していきます。
![トリガー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/198dfc48-759f-188e-ce15-8c7695295a9b.jpeg)

新規API作成 > REST APIを選択します。
セキュリティはオープンを選び、右下の追加ボタンをクリックしてトリガーを登録します。

![apigateway.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/9d660eb3-e8ef-773a-cb06-6b20e08ddc25.png)

ここまでで、API Gatewayの大枠の設定が完了しました。
ここからは、さらにエンドポイントの詳細を設定していきます。

![slack-attendance-naberina_-_Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/aae61f97-4785-10c8-2c80-5a6741223894.png)

#### メソッドANYを削除する
今回はHTTPメソッドPOSTのみ使用するため、デフォルトのANYメソッドは削除しておきます。
![any.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/8b64330e-ee44-a8b2-82bc-b6896d9d245e.png)

#### POSTメソッドを作成する
アクションボタンから、メソッドを作成します。POSTメソッドを作成したら、呼び出したいLanbda関数を設定しておきましょう。
![gateway詳細設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/c51cf5f5-9163-52f9-9070-913332a0b800.png)

#### APIのデプロイ
アクションボタンからAPIのデプロイを選択します。
デプロイしたいステージは、適当な名前をつけてデプロイしましょう。
(例: 本番用ならprod, ステージング用ならstgなど)
![デプロイ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/d34075a0-fefa-eab3-9d95-b8aae02414a9.png)
画像の①と②を合わせたURLをkintone Webhook URLに登録する
![url.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/d10e5f6a-76a7-fbe7-3ff7-7cdfeb88a0bb.png)

### 6. kintone WebhookにURL登録
デプロイしたAPIGatewaymのURLをkintoneのWebhookに登録します。
Webhook URL: `https://*******.amazonaws.com/デプロイしたステージ名/ディレクトリ名`
![Webhookの追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/68cdef8a-6471-545d-c00b-6fbf3623e2ea.png)


### 7. 動作確認(kintoneに1件データを登録)

kintoneにレコードを1件登録してみましょう。
以下のように、Slackにメッセージが届きます。
![slack通知.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/1649cb8e-03a3-c814-8030-fdb13b2651c5.png)

設定は以上で終了です。お疲れ様でした🎉
うまくSlackに通知することができましたか。

もし通知が届いていない場合は、kintoneのWebhook URLに誤りがないか、
コードミスはないか確認してみて下さい。また、ご自身でデバッグする際のヒントを下記でご紹介します。

## 🚀 デバッグ

### AWS Lambdaのデバッグ方法

Lambdaの実行ログは、対象のCloudWatchに書き出されています。
そのため、CloudWatchのログを確認しながらLambda上のコードをデバッグをします。
![cloudwatch-log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/ba32bbbb-aff4-7b08-e150-79003fe3d912.png)

表示したいログ内容は、自身でLambdaのコードに`console.log`を書いておきましょう。

#### 対象のCloudWatch
①CloudWatch を表示し、②ロググループ の検索窓から確認したい ③Lambda関数 を検索します。
![cloudwatch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168550/590eda51-5313-dbb6-0241-6fa6ca7347ac.png)

詳細画面のLog streamにLambdaの実行ログが記録されているため、
console.logを用いて、eventオブジェクトの中身等を確認してみてください。