GASとLINE Messaging APIとNotion APIで、LINEからNotionにメモ登録できるようにしてみた

## はじめに

こんにちは、エンジニア歴1年半のGopherくんLoverなペーペーエンジニアです。

2週連続で書くことになったので、ちょっと今回はAnalyticsから離れてみようと思います。
誠に個人的な話なのですが、最近Notionを使い初めまして、使いやすさに感激しているところです。

そんなNotionなので、普段ふとした時のメモにも使いたい！と思うのですが、いちいち開くのも…
と思ったことがあり、最近APIも熱そうなイメージもアリ…

連携して簡単に入力できないか…？
という感じでちょっと作成してみたので、その内容をまとめたいと思います。

タイトルにある通りですが、LINEに連携してメッセージ送信した内容をメモとして登録しちゃえ！という内容です。

完全にプライベートでやったので、突っ込みどころは多いかもしれませんが、そこのところはご容赦ください。
では、いきましょーう。

#### ～本日の流れ～
>**⓪LINE Messaging APIとNotion APIの導入について**
>**①NotionDBへのデータのアップロード(Notion API)**
>**②LINEメッセージからのデータ取得(LINE Messaging API)**
>**③上二つの結合！**

## ⓪LINE Messaging APIとNotion APIの導入について
#### 【LINE Messaging APIの導入】
LINE Messaging APIの導入に際して必要になるアカウント発行などについては、こちらを参考にしてください。

https://developers.line.biz/ja/docs/messaging-api/getting-started/

上記の流れでLINEビジネスアカウントを作成し、チャネルアクセストークンを発行します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/ebaaec02-7bc0-ab4c-0f15-4c7b009257e2.png" width="800">

Messaging API設定欄を下に行くと…


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/d07f9789-fcc7-c853-2a22-c8f9734d73a8.png" width="800">

チャネルアクセストークンの欄があるので、そこで発行してください。

その上でGASでメッセージを取得する処理を書いて、Webhook URLを設定すればよいです。
導入に関してはここまでなので、一旦発行したチャネルアクセストークンを保存しておきます。

#### 【Notion APIの導入】

続いて、Notion APIです。
こちらも公式に沿って進めていただければ発行できます。

https://www.notion.so/ja-jp/help/create-integrations-with-the-notion-api

上記のようにインテグレーションを作成し、ページへのコネクトを追加します。
※インテグレーションは↓ここ↓から作成可能です！

https://www.notion.so/my-integrations

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/b829e003-5450-e739-4269-b01bd3261c21.png" width="600">

新しいインテグレーションを選択し、もろもろの情報を設定したのち、送信を押下

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/83c27aea-57de-b695-5147-f9c8b44ef149.png" width="600">

トークンが作成されるので、表示してコピーしておいてください。(後ほどGASで使います！)

その後、情報を挿入したいページにコネクトを追加します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/7e98c655-a3fc-313b-5652-451606171d0d.png" width="600">

導入は以上です！

### ※ちなみに

GASではスクリプトプロパティ設定が可能なので、先ほど取得したトークなどは設定しておくと後々便利です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/35c3924e-47ae-d814-d573-1053f831eee6.png" width="800">

設定画面を開き、LINEのチャネルアクセストークン、NotionのAPIトークンとDB IDを保存しておきます。
※NotionのDB IDは、挿入したいページのURLのうち、スラッシュから?vまでの部分です。
　「https\://www.notion.so/``ここの部分``?v=#############」

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/55d3e472-0092-2553-3fa2-c4125df6e2a0.png" width="600">



## ①NotionDBへのデータのアップロード(Notion API)

つづいて、まずはNotion側のGASを書きます。
挿入したい内容をデータベースIDとともにjsonにし、トークンなどをoptionsに着けてUrlFetchAppします。

今回は、メモとして、以下の4つのプロパティを設定することにします。

・タイトル
・メモ
・ジャンル
・リンク

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/af56db06-6520-69c6-3e9f-c2f373513bb1.png" width="800">

json形式でプロパティ値を送信するのですが、プロパティの種類によって記法が違うので、もし別のものを使用したければこちらを参照ください。

https://developers.notion.com/reference/page-property-values

【実装したコード】
```javascript
function addDataToNotion(splitedMessage) {    // splitedMessageとしてLINEで入力された値が来る想定

  // 一旦は仮のデータを設定
  var insertData = [
    "ネコちゃん", 
    "かわいい", 
    "保存用",
    "https://www.google.com/search?q=%E3%83%8D%E3%82%B3&rlz=1C1PWSB_jaJP1030JP1030&source=lnms&tbm=isch&sa=X&ved=2ahUKEwjOrYumuc79AhUT82EKHXZ-BK4Q_AUoAXoECAEQAw&biw=1920&bih=947&dpr=1"];

  // スクリプトプロパティに格納したデータベースID、トークンを取得
  const props  = PropertiesService.getScriptProperties();
  const dbId   = props.getProperty('NOTION_DB_ID');
  const token  = props.getProperty('NOTION_TOKEN');

  const apiUrl = 'https://api.notion.com/v1/pages';

  // json形式のオブジェクトを作成
  let pageObj = {
    parent: {
      database_id: dbId,
    },
    properties: {
      "タイトル": {
        "title": [{
          "text": {
            "content": insertData[0];
          }
        }]
      },
      "メモ": {
        "rich_text": [{
          "text": {
            "content": insertData[1];
          }
        }]
      },
      "ジャンル": {
        "select":
        {
          "name": insertData[2];
        }
      },
      "リンク": {
        "url": insertData[3];
      }
    }
  }

  // optionsに必要な情報を設定
  const options = {
    method: "POST",
    headers: {
      "Content-type": "application/json",
      "Authorization": "Bearer " + token,
      "Notion-Version": '2022-06-28',
    },
    payload: JSON.stringify(obj),
  };

  //NotionAPIにポストでアクセスし、DBにデータを挿入
  try {
    let response = UrlFetchApp.fetch(apiUrl, options);
    let result = response.getResponseCode()

    // 成功の場合は200を返却
    if (result != "200") {
      result = response.getContentText("UTF-8")
    }

    return result;
  } catch (e) {
    // エラー文を返却
    let result = e;
    return result;
  }
}
```

これで実行すると…

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/f80f1684-6bd9-2ef9-3afe-a0a970955ed2.png" width="800">

データが挿入されます！

これでNotion側はOKなので、後はここにLINEからデータを送れるようにするだけです。

## ②LINEメッセージからのデータ取得(LINE Messaging API)

続いてラインです！
先程、LINE Messaging APIは導入しましたので、まずは簡単な返信Botを作ってみましょう。

メッセージはjsonデータとして送られてくるので、それを受け取ってそのまま返すコードです。

【実装したコード】
```javascript
function doPost(e) {
  // スクリプトプロパティに格納したLINE Messaging APIのチャネルアクセストークンを取得
  const props  = PropertiesService.getScriptProperties();
  let token = props.getProperty('LINE_M_API_TOKEN');

  // 取得したJSONデータを取得
  let eventData = JSON.parse(e.postData.contents).events[0];

  //取得したデータから、応答用のトークン・メッセージを取得
  let replyToken = eventData.replyToken;
  let message = eventData.message.text;

  // 返信用のAPI URL
  let url = 'https://api.line.me/v2/bot/message/reply';
    
  // 返信メッセージを用意(取得したメッセージをそのまま代入)
  let replyMessage = message;

  // payloadに返信用トークンとメッセージを設定
    let payload = {
      'replyToken': replyToken,
      'messages': [{
          'type': 'text',
          'text': replyMessage
        }]
    };

    // optionsにPOST設定、チャネルトークン、jsonを設定
    let options = {
      'payload' : JSON.stringify(payload),
      'myamethod'  : 'POST',
      'headers' : {"Authorization" : "Bearer " + token},
      'contentType' : 'application/json'
    };

    //LINE Messaging APIにリクエストし返信
    UrlFetchApp.fetch(url, options);
}
```

LINEからWebhookを使用してGASを動かすので、デプロイします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/e7f2d3be-a520-5235-2644-1201b4e737c7.png" width="600">

新しいデプロイを選択し、左側上部の歯車からウェブアプリを選択し、デプロイします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/2d4c0d6f-8a52-db6e-96a1-425c50d5b6e0.png" width="400">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/2bdbd348-c8f0-232c-c786-910b72a40f6d.png" width="400">

完了したら、ウェブアプリの欄にあるURLをコピーして、LINE Messaging APIに設定します。
先程の、LINE Messaging APIの設定画面を開き、先ほどのURLを設定してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/a10926ae-c065-2b51-dadc-f594c517afeb.png" width="800">

これで、メッセージを送った際にGASが動くようになりました。

試しにやってみると…

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/36671217-efc7-6cb1-d3c1-32d9e68e31b4.jpeg" width="400">

こんな形でちゃんと返ってきていればオッケーです！

## ③上二つの結合！

では最後に、LINE→Notionメモの挿入を作成します。
上記で記載したコードを少し編集していきます。

変更した内容としては以下の2点です。

・LINEメッセージの内容を改行で分割
・NotionAPIの実行可否をreturnし、失敗の場合はLINEメッセージにエラー情報を投下

変更したうえで、早速動かしてみると…

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/77f3a2c8-46cd-a5c0-d4f2-5158116b228b.jpeg" width="400">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711450/4eb59169-bc39-f09e-9c41-55f65ac2355a.png" width="800">

問題なく追加されていました！

以下、最終的に実装した内容になります。
【実装したコード】
```javascript
function doPost(e) {
  // スクリプトプロパティに格納したLINE Messaging APIのチャネルアクセストークンを取得
  const props  = PropertiesService.getScriptProperties();
  let token = props.getProperty('LINE_M_API_TOKEN');

  // 取得したJSONデータを取得
  let eventData = JSON.parse(e.postData.contents).events[0];

  //取得したデータから、応答用のトークン・メッセージを取得
  let replyToken = eventData.replyToken;
  let message = eventData.message.text;

  // メッセージを改行ごとに分ける
  let splitedMessage = message.split(/\r\n|\n/);

  // Notionにデータを追加
  let result = addDataToNotion(splitedMessage);

  // 応答メッセージ用のAPI URLを定義
  let url = 'https://api.line.me/v2/bot/message/reply';

  if (result != "200") {
    //ユーザーからの投稿メッセージから応答メッセージを用意
    let replyMessage = "エラーにより失敗しました。\nエラー情報：" + result;

    // payloadに返信用トークンとメッセージを設定
    let payload = {
      'replyToken': replyToken,
      'messages': [{
          'type': 'text',
          'text': replyMessage
        }]
    };

    // optionsにPOST設定、チャネルトークン、jsonを設定
    let options = {
      'payload' : JSON.stringify(payload),
      'myamethod'  : 'POST',
      'headers' : {"Authorization" : "Bearer " + token},
      'contentType' : 'application/json'
    };

    //LINE Messaging APIにリクエストし返信
    UrlFetchApp.fetch(url, options);
  } else {
    //ユーザーからの投稿メッセージから応答メッセージを用意
    let replyMessage = "登録しました！\r\nURLをチェック：NotionのURL";

    // payloadに返信用トークンとメッセージを設定
    let payload = {
      'replyToken': replyToken,
      'messages': [{
          'type': 'text',
          'text': replyMessage
        }]
    };

    // optionsにPOST設定、チャネルトークン、jsonを設定
    let options = {
      'payload' : JSON.stringify(payload),
      'myamethod'  : 'POST',
      'headers' : {"Authorization" : "Bearer " + token},
      'contentType' : 'application/json'
    };

    //LINE Messaging APIにリクエストし返信
    UrlFetchApp.fetch(url, options);
  }
}

function addDataToNotion(splitedMessage) {

  //スクリプトプロパティに格納したデータベースID、トークンを取得
  const props  = PropertiesService.getScriptProperties();
  const dbId   = props.getProperty('NOTION_DB_ID');
  const token  = props.getProperty('NOTION_TOKEN');

  const apiUrl = 'https://api.notion.com/v1/pages';

  //データベースIDを渡しオブジェクトを生成
  const obj = generateObj(dbId, splitedMessage);

  //NotionAPIにポストしデータを追加
  const options = {
    method: "POST",
    headers: {
      "Content-type": "application/json",
      "Authorization": "Bearer " + token,
      "Notion-Version": '2022-06-28',
    },
    payload: JSON.stringify(obj),
  };

  try {
    let response = UrlFetchApp.fetch(apiUrl, options);
    let result = response.getResponseCode()

    // 成功の場合は200を返却    
    if (result != "200") {
      result = response.getContentText("UTF-8")
    }

    return result;
  } catch (e) {
    // エラー文を返却
    let result = e;
    return result;
  }
}


function generateObj(dbId, splitedMessage) {

  var title = splitedMessage[0];
  var text= splitedMessage[1];
  var genre = splitedMessage[2];
  var url = splitedMessage[3];

  let pageObj;

  // urlのみ必須ではないので、条件分岐でオブジェクトを作成
  if (url != null) {
    pageObj = {
      parent: {
        database_id: dbId,
      },
      properties: {
        "タイトル": {
          "title": [{
            "text": {
              "content": title
            }
          }]
        },
        "メモ": {
          "rich_text": [{
            "text": {
              "content": text
            }
          }]
        },
        "ジャンル": {
          "select":
          {
            "name": genre
          }
        },
        "リンク": {
          "url": url
        }
      }
    }
  } else {
    pageObj = {
      parent: {
        database_id: dbId,
      },
      properties: {
        "タイトル": {
          "title": [{
            "text": {
              "content": title
            }
          }]
        },
        "メモ": {
          "rich_text": [{
            "text": {
              "content": text
            }
          }]
        },
        "ジャンル": {
          "select":
          {
            "name": genre
          }
        }
      }
    }
  }

  return pageObj;
}

```

## まとめ

以上、「GASとLINE Messaging APIとNotion APIで、LINEからNotionにメモ登録できるようにしてみた」でした。
今回はとりあえず動けばいいと思って作ったので、細かいところは後々改善していこうと思います。

やはりAPIって楽しいですね。
LINE Messaging API使って無限にほめてくれるLINE Botで作ろうかな…(ありそう)

LINEとNotion、どちらもAPIとしてはバリエーションがありそうなので、ご興味ある方はぜひ見てみてください！