kintoneでフィールドが特定の値に変更された時にSlack通知する設定とJavaScriptサンプルコード

# 前口上

Kintoneを使ってアプリを作成する中で、特定のイベントが発生したときに通知を送りたいと思ったことはありませんか？そんな時、KintoneにはデフォルトのWebhook機能が用意されています。でも、実はこれに少し制約がありました。

## デフォルトのWebhookはちょっと物足りない

また、KintoneにはデフォルトでWebhookが設定できますが、細かい条件を設定するのが難しい模様。
（というデフォルトだと何故か成功しないのですが私だけでしょうか）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/794a67ba-d80a-fd95-c27c-24e1d5c8b673.png)

例えば、「このフィールドが特定の値に変わった時だけ通知したい！」みたいな場合、
デフォルト設定ではちょっと難しい。

じゃあJavaScriptだ！

## CORSの壁にぶつかる

何も考えずにJavaScriptを用いると、CORS制限に引っかかります。
これは異なるオリジン（プロトコル（httpやhttps）、ホスト名（cybozu.comやslack.com）、ポート番号のこと）でリソースを共有することを制限するCORS（クロスオリジンリソースシェアリング）というものです。
例えば、Kintone（`cybozu.com`）からSlack（`slack.com`）に直接リクエストを送ろうとすると、CORSポリシーに引っかかってしまいます。結構面倒です。

### kintone.proxyで解決！

そこで登場するのが**kintone.proxy**。
これを使うと、Kintoneが外部サービスにリクエストを代理で送ってくれるので、CORSエラーを回避できます。これのおかげで、`AWS Lambda`や`GCP Cloud run`などを用意することなく、Slackなどにスムーズに通知を送ることができます。


:::note info
ただし、指定した時間に実行みたいなのは、kintone側にその機能がないので`AWS Lambda`や`GCP Cloud run`などが必要になるようです（業務終了時に集計とかは…）。
:::


そのため、**kintone.proxy**を用いつつ、JavaScriptを使うことによって、柔軟かつ複雑な条件での通知をkintoneからSlackへと送ることが可能になりました。

なお、Slackのwebhookの作成については下記の方の記事が参考になりましたので、
まだSlackのwebhookを作っていない方は一読してみると良いかもしれません。
（意外とSlack管理画面の場所が分からず迷いました）

https://qiita.com/ik-fib/items/b4a502d173a22b3947a0

# 本題（コードサンプル）

## レコードのフィールドが特定の値に変更されたときのみ通知

```javascript
(function () {
    const subdomain = 'yourDomain'; // あなたのkintoneのサブドメイン
    const appId = '123'; // あなたのkintoneのアプリID
    const targetFieldCode = 'yourFieldCode'; // 監視するフィールドコード
    const specificValue = 'yourValue'; // 監視するフィールドコードの値
    const webhookUrl = 'yorSlackWebhookToken'; // Slack Webhook
    let oldValue; // 監視対象のフィールドコードの旧値を保持する変数
    // メッセージに含みたいフィールドコードIDがあれば追加で変数を定義する

    // 編集画面が表示されたときに発火するイベント
    kintone.events.on('app.record.edit.show', function (event) {
        // 監視対象のフィールドコードの旧値を取得
        oldValue = event.record[targetFieldCode].value;
    });

    // 保存ボタンが押されたときに発火するイベント
    kintone.events.on('app.record.edit.submit', function (event) {
        // 現在のフィールドの値を取得
        const currentValue = event.record[targetFieldCode].value;

        // 監視するフィールドの値が旧値から変更されていて、なおかつ指定した特定の値に等しい場合のみ、Slack通知する処理を続行する
        if (currentValue !== oldValue && currentValue === specificValue) {
            // 対象レコードのURLを取得（メッセージ用）
            const recordId = event.recordId;
            const recordUrl = `https://${subdomain}.cybozu.com/k/${appId}/show#record=${recordId}`;

            // Slackに送信するメッセージ
            const message = {
                text: `フィールド ${targetFieldCode} の値が ${specificValue} に変更されました。\n
                対象レコード：${recordUrl}`
            };

            // kintone.proxyを使用してSlack APIにPOSTリクエストを送信
            const body = JSON.stringify(message);

            const requestOptions = {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: body
            };

            // kintone.proxyでリクエストを実行
            kintone.proxy(webhookUrl, requestOptions.method, requestOptions.headers, requestOptions.body)
                .then(function (response) {
                    console.log('Slackへの通知に成功:', response);
                })
                .catch(function (error) {
                    console.error('Slackへの通知に失敗:', error);
                });
        }

        return event; // 処理を続行
    });
})();
```

- 変更前と変更後の値が同一の場合は通知しない
    - これが当初は前後の値を別に取得し保存するなど難解に考えてましたが、
    `let oldValue;`で編集画面を開いたタイミングで変更前の値を取得し、
    保存クリック時に比較することでその問題は簡単にクリアしました。
- 通知の際には変更内容およびそのレコードのURLも通知する
- この方式だとWebhookトークンをjsに埋め込んでいるので若干のセキュリティ懸念も。
    - そういった面を踏まえると、Lambdaなどにおいて環境変数で読み込む方がより万全とは思います。

▼フィールドを変更されるとこのように通知が来ます（Slack管理画面からアイコンを変更するとカワイイ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/eb5e4d2f-eb6b-1101-505c-9b80b749ae2a.png)

# 後書き

Slack文化が浸透している会社でkintoneを使っているため、
Slack通知の相談が相次いでいるものの、Slackの管理者ではなく、
Webhookの作成ができなかったため、個人で試してみました。

思いのほか苦戦しましたが、上記コードを変えることで
色々な形に対応できそうなので改変しつつ長く使っていきたいと思います。