GASでwebhook使ってnotionのページ更新を知らせるツール作った

# GASでwebhook使ってnotionのページ更新を知らせるツール作った

GAS(google app script)でnotionのページ更新をdiscordで通知してくれる機能を作ったので覚書として投稿します

## 作ったもの


毎日0:00に、24時間以内に指定のnotionページで新規ページ作成があったかどうかをdiscordで通知してくれます

notion側↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858351/5e16bbf1-7046-4b47-bd36-8a13b83c5350.png)


discord側↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858351/d7615a37-778a-4ff4-96b1-dc2c2f6948bb.png)

## 使ったもの


- GAS（google app script）→**javascript**言語
- notion及びnotion API
- discord webhook

## 今回のポイント


**実行が1日に1回**なので、GASの無料版でも問題なく使える

discordでのメッセージ送信に**webhook**という機能を使ったので、botよりも比較的簡単な（短い）コードで実装できた。

notionの返答データ（JSON）のobject構造が複雑なため、それを可視化できるツールが欲しいと感じた。

## 仕組み


説明が言葉では難しいので図を用意します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858351/b130f660-652d-4dc1-bc38-da905c567340.png)


このようにnotion APIから取得したデータを加工し、条件に合わせて出力をdiscordに行います。

説明は省略しますが、notionのAPIを使うにはnotion側で手続きが必要です。

## webhookとは？


discordなど多くのアプリケーションに存在する機能。webアプリケーションでイベントが発生したときにメッセージを送信できる。今回ではGASのスクリプトからdiscordへのメッセージ送信で利用する。

webhookはいわゆる”ツール”のようなものではなく、例えばdiscordでは`https://discord.com/api/webhooks/xxxx`のようにURLが用意されていて、このURLをメッセージ内容と合わせて送信をすることで実現される。このwebhookURLは**チャンネル**ごとに別のものを使う。

- APIとの違い

webhookはAPIとは違い、一方向のみの操作であることが特徴。APIは要求・応答のセットだが、webhookはスクリプトから対象アプリへの送信のみである。

## 機能の流れ


①GAS→notionへデータを要求

➁notion→GASにデータを返答

③GAS上でデータ処理・条件に応じたメッセージを作成

④作成したメッセージをwebhookを用いてdiscordに送信

### ①GAS→notionへデータを要求

### ➁notion→GASにデータを返答

[こちらの記事](https://zenn.dev/ivry/articles/71ff886cf16fbd) を参考にnotionからデータをjson方式で取得します。

```jsx
function fetchNotionDatabase() {
    const props = PropertiesService.getScriptProperties();
    const NOTION_API_KEY = props.getProperty('NOTION_API_KEY');
    const DATABASE_ID = props.getProperty('NOTION_DATABASE_ID');

    const url = `https://api.notion.com/v1/databases/${DATABASE_ID}/query`;

    const options = {
        method: 'post', // Notion API の `query` は POST リクエスト
        headers: {
            'Authorization': `Bearer ${NOTION_API_KEY}`,
            'Notion-Version': '2022-06-28',
            'Content-Type': 'application/json'
        }
    };

    // リクエスト、結果
    const response = UrlFetchApp.fetch(url, options);
    const data = JSON.parse(response.getContentText());
    //Logger.log(data);

    return data;

}
```

### ③GAS上でデータ処理・条件に応じたメッセージを作成

```jsx
// 24時間以内のページを取得
let msgcontent = [];
for (let i= 0; i < data.results.length; i++){
    const timestamp = data.results[i].last_edited_time;
    if(isWithinLast24hrs(timestamp)){
        msgcontent.push(getTitle(data.results[i]));
    }
}
```

今回、24時間以内の編集があった記事を取得したいので、更新または新規作成のあった記事のタイトルを取得します。

### ④作成したメッセージをwebhookを用いてdiscordに送信

```jsx
// 出力メッセージ部
let date = new Date();
date.setDate(date.getDate() - 1); //00:00更新なので前日の日付
const datestring = formatDate(date);

if (msgcontent.length === 0){
    Logger.log(datestring +"\n本日の更新はありません");
    msgsend(datestring +"\n本日の更新はありません");
}else{
    Logger.log(datestring +"\n本日の更新タイトル:"+ msgcontent);
    msgsend(datestring +"\n本日の更新タイトル:"+ msgcontent);
}
```

③の `msgcontent` を基に送信メッセージを決定します。

`msgsend()`関数

```jsx
function msgsend(msgcontent) {
    const props = PropertiesService.getScriptProperties();
    const DISCORD_WEBHOOK_ID = props.getProperty('DISCORD_WEBHOOK_ID')
    const WEBHOOK_URL = `https://discord.com/api/webhooks/${DISCORD_WEBHOOK_ID}`; 

    let payload =
    {
      "content": msgcontent
    };

    let options =
    {
      "method": "post",
      "payload": payload
    };

    UrlFetchApp.fetch(WEBHOOK_URL, options);
}
```

これで新規・更新のあったページ情報をdiscordで送信できます。

## 機能を毎日決まった時間に実行する



GASの**トリガー**という機能を使って、毎日0:00に実行するよう指定します。

[こちらの記事](https://auto-worker.com/blog/?p=6383) から、スクリプト内でトリガーを操作する方法が載っているので参考にしました。任意の関数内でトリガーを登録して、次回の実行日時を指定します。今回では次の日の0:00に再度実行してほしいため、`new Date()` で日付取得したデータを適切に加工します。

```jsx
//新しいトリガー作成
    let targettime = new Date();
    targettime.setDate(targettime.getDate() + 1); //翌日00:00
    
    //時刻
    targettime.setHours(00);
    targettime.setMinutes(00);
    targettime.setSeconds(00);
    //newTriggerメソッドでmain関数実行を特定日時でトリガー登録
    Logger.log("targettime:"+targettime);
    ScriptApp.newTrigger('main').timeBased().at(targettime).create();
```

実行した時点での日時を取得し、翌日の00:00:00に加工します。その後、GASのメソッドを呼び出して、「main関数を時間実行するトリガー」を作ります。

## まとめ


今回はnotionのAPIとDiscordのWebhookという機能を使いました。今回は一方向の機能ですが、今後はDiscord側でBotを用いて双方向な機能も作りたいです。例えば、ランダムなページを紹介してくれるツールなどが作る候補になると考えています。Webhookは簡単にメッセージを送ることができる機能なのでぜひ使ってみてください。