GASでNotionAPIを叩いてSlackに締め切りお知らせくん(リマインダ)を作ろう

Notionのデータベースの特定の列をチェックして、Slackにリマインドするツールを作ったので解説と、そのテンプレを公開しておきます。

### テンプレ
https://github.com/Suyama-Daichi/NotionReminder

## 解説
### アーキテクチャ
至ってシンプルです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/f1eefff6-dfce-fa2f-2163-176c0ff782e8.png)

### 環境
> 使用言語: TypeScript
> プラットフォーム: Google Apps Script
> デプロイツール: Clasp

## 気づき・落とし穴
### ⚠ import / export を使うときは、`namespace` を使う
GASはV8エンジンに対応しているので、ES6の記法は基本的に使えるものが多いですが、 `import / export` は対応していません[*1](https://officeforest.org/wp/2020/02/06/google-apps-script%E3%81%AEv8-runtime%E5%AF%BE%E5%BF%9C%E3%82%92%E6%A4%9C%E8%A8%BC%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/#V8)。

じゃあファイル分割できないやん！というわけでもなく、namespaceを使えば一応ファイル分割して別ファイルからモジュールをimportできます。

> (日本語解説) [Google Apps Scriptのモダンな開発環境は理想だった - ファイル分割するとimport/export使えない問題](https://kenchan0130.github.io/post/2019-12-25-1#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B%E3%81%A8importexport%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%E5%95%8F%E9%A1%8C)
> (公式) [clasp/typescript.md at master · google/clasp - Modules, exports and imports](https://github.com/google/clasp/blob/master/docs/typescript.md#modules-exports-and-imports)

### ⚠ pushするファイルの順番に注意
GASではファイルが上から読まれます。
なので、グローバル変数・関数は呼び出し元より先になるようにpushしなければなりません。

Claspでは、`.clasp.json`の`filePushOrder`でpushするファイルの順番を保証してあげたほうがいいでしょう(指定しなければアルファベット順？)

> 🔔 指定しなければ、一番最後にpushされるので、`main.ts`は指定してません。

```
  "filePushOrder": [
    "src/Constants.ts",
    "src/Convert.ts",
    "src/NotionApi.ts",
    "src/SlackApi.ts"
  ]
```
> [Google Apps ScriptのV8 Runtime対応を検証してみた – 🌴 officeの杜 🥥](https://officeforest.org/wp/2020/02/06/google-apps-script%e3%81%aev8-runtime%e5%af%be%e5%bf%9c%e3%82%92%e6%a4%9c%e8%a8%bc%e3%81%97%e3%81%a6%e3%81%bf%e3%81%9f/#comment-158)
> (公式) [google/clasp: 🔗 Command Line Apps Script Projects](https://github.com/google/clasp#filepushorder-optional)

### ⚠ npmパッケージは使えないと思ったほうがいい
今回、NotionAPIを利用するにあたって[notion-sdk-js](https://github.com/makenotion/notion-sdk-js)を使おうとしていたのだが、webpackやbabelでゴリゴリに構成しなければなりません。

ちゃんと構成すれば使えるnpmパッケージもあるのですが、NotionSDKの場合は使えませんでした。
> [Google Apps Scriptのモダンな開発環境は理想だった - npmライブラリが種類によってGASでは動かない問題](https://kenchan0130.github.io/post/2019-12-25-1#npm%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%8C%E7%A8%AE%E9%A1%9E%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6gas%E3%81%A7%E3%81%AF%E5%8B%95%E3%81%8B%E3%81%AA%E3%81%84%E5%95%8F%E9%A1%8C)

じゃあdotenvを使いたいときはどうすればいいのか、後述します。

### 環境変数・アクセストークンの管理について
先述の通り、npmパッケージが使えない(今回は使わない)ので`dotenv`が使えません。
とはいえ、Notion、Slackのアクセストークンをソースコードに直接書くわけにもいきません(Githubなどに公開できません)

しかし大丈夫です。GASには、スクリプトプロパティという仕組みで環境変数を呼び出せます。

> [【GAS】コードにAPIトークンやIDのベタ書きを避ける（プロパティサービスの活用） - Qiita](https://qiita.com/massa-potato/items/2209ff367d65c5dd6181)

### 👍 TypeScriptはそのまま書ける
TypeScriptはそのまま書けます。

`clasp push`でpushするときに、claspがトランスパイルしたものをpushしてくれます。神

> [clasp/typescript.md at master · google/clasp](https://github.com/google/clasp/blob/master/docs/typescript.md#typescript)

## 使い方・事前準備
### 事前準備
1． SlackのIncoming Webhookを設定する

> [Sending messages using Incoming Webhooks | Slack](https://api.slack.com/messaging/webhooks#)

2． NotionToken,DatabaseIDを取得する
NotionTokenの取得
インテグレーションを作成すると得られる、`Internal Integration Token` がアクセストークンです
![2ec137d-093ad49-create-integration.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/234029fa-85f4-7ad7-7809-30ee749b0ea6.gif)

> (公式) [Getting started - Step 1: Create an integration.](https://developers.notion.com/docs/getting-started#step-1-create-an-integration)

DatabaseIDの取得
Databaseの共有リンクにあります。

```
https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
                                  |--------- Database ID --------|
```
> (公式) [Getting started - Step 2: Share a database with your integration](https://developers.notion.com/docs/getting-started#step-2-share-a-database-with-your-integration)

3． スクリプトプロパティに1,2で取得したトークン、DatabaseID、webhook urlを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/77103b87-3f9c-d797-a082-62fd571b17c6.png)

4． Notionの列名を指定する
> 🔔 ここからはコード依存なので、自身で要件や業務仕様に合わせて実装して構いません。

`src/main.ts`に、チェック対象となるNotionの列名を指定します。
`displayColumnName`は終了する対象の表示名です。

> 例
> こういうデータベースを作ったとしたら
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/7fff197c-66d3-fcdc-4afe-6ceccbfd89a7.png)
> `displayColumnName`に`契約名`
> `targetColumnName `に`契約終了日`
> を2021/12/1に実行すると、
> `Test契約の終了日まで23日です`と出力されます


```typescript
/** 監視対象の表示名 */
const displayColumnName = '契約名'
/** 監視対象の列名 */
const targetColumnName = '契約終了日'
```

### 実行する
GAS側で`doPost`関数を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/4f1b7b79-09d4-94bb-a00e-fa6c8dc7583b.png)

こんな感じで通知されます