Google FormsからNotionのデータベースに回答結果を保存する

[Fusic Advent Calendar2023](https://qiita.com/advent-calendar/2023/fusic) 16日担当の小林です。
（17日まであと20分ですがまだ16日ですのでユルシテ）

今回やるのはGoogle Formの回答結果をNotionのデータベースに書き込む方法です。

Google Formからスプレッドシートに保存されるからいいじゃん！と思いますが、例えば質問フォームなどを作って質問に対する回答のタスク管理もしたい場合、
スプレッドシートよりNotionのほうがBoardViewなどを使ってステータス管理しやすのでは？＆NotionAPIとGAS使ったことなかったので今回を機会に触ってみよう!回になります。

# Notionの準備

## 1. Notionで回答結果を書き込むデータベースを用意

- Notion使い慣れてるひとはサクッと作れると思いますがデータベースを作成します

![スクリーンショット 2023-12-16 22.07.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/0934d22a-f1a3-f4da-731e-3ae19ebae374.png)

- 作成後、ShareボタンからCopy Linkボタンを叩いて、どこかにメモとして貼り付けておきます

![スクリーンショット 2023-12-16 22.12.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/0c8f3db3-4947-f5c2-22ff-ef2a9609cf9d.png)

- 自分の場合こんな感じで取れました
```
# https://www.notion.so/{database_id}?v={view_id}&pvs={?}
https://www.notion.so/XXXXXXXXXXXXXXXXX?v=YYYYYYYYYYYYYYYYYYYYYY&pvs=Z
```
-  `database_id` をメモしておきます

## 2. NotionAPIに必要なインテグレーションの設定を行う

- インテグレーション用のURLにアクセスします
    - https://www.notion.com/my-integrations
- インテグレーションを追加します
![スクリーンショット 2023-12-16 22.16.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/096a123b-2993-59d1-a275-33f08c73ec10.png)
- インテグレーションを作成すると `シークレット` が発行されるのでこれもメモしておきます
    - ドキュメントにNOTION_API_KEYって書いてて、シークレットと同じなのか最初混乱しました（笑。これがNOTION_API_KEYになります
![スクリーンショット 2023-12-16 22.19.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/d47e91ee-29ba-37b6-968b-4d01381f2358.png)

- 次にこのインテグレーションと1で作ったデータベースを紐づけます
    - 先程作ったデータベースに移動し、設定ボタンの `Connections` から AddConnectionsを選択するとリストの中に先程作ったインテグレーションが表示されます。これを選択すると以下のようにConnectionに追加されます
![スクリーンショット 2023-12-16 20.35.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/1fb28179-54f0-bf4f-502c-70ebf4c29abf.png)

## 3. API送信実行(curl)

- これでNotion側の準備が終わったのでcurlして追加されるか試してみます
    - シークレットとdatabase_idを貼り付けます

```
curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"{シークレット}"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2022-06-28" \
  --data '{
	  "parent": {
      "type": "database_id",
      "database_id": "{database_id}"
    },
	  "properties": {
      "Name": {
        "type": "title",
        "title": [
          {
            "type": "text",
            "text": {
              "content": "New Page Title"
            }
          }
        ]
      }
    }
  }'
```

- これで成功すれば以下のように追加されます
![スクリーンショット 2023-12-16 22.26.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/bc7bbac1-ad38-15ba-81ed-0a7e87d01922.png)

- databaseのカラムの型によってパラメタの記述方法が異なるのでそのあたりはドキュメントを参照してください
    - ドキュメント
        - https://developers.notion.com/reference/database

# Google Formの準備

## 1.Formの作成

- Notion側は準備できたので次にGoogle Formsで新しいフォームを作ります
    - とりあえずテキトーなフォームを作ります
![スクリーンショット 2023-12-16 22.28.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/deb188c8-a356-5020-c962-8a270ef914be.png)

## 2.GASの作成

- Formで回答した際に、NotionAPIにリクエストをどうやって送ればいいの？と思って調べたらGAS(Google Apps Script)でスクリプトを書くことで出来ました。
    - GASの作成は先程作ったGoogle Formsの右上の設定ボタンから表示されるスクリプトエディタを選択することで作成ページに飛べます
![スクリーンショット 2023-12-16 21.20.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/e0ba56f4-71e6-3082-22a6-9e980ba7a9d7.png)
- もうスクリプト書いてる状態ですが以下のようなGASエディタ画面が表示されます
![スクリーンショット 2023-12-16 22.41.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/01230920-a81c-ee29-a080-0e8af0e4681d.png)

### コードの記述

- 手っ取り早く、実際に動いたコード貼っときます

```
function onFormSubmit(event) {
  // フォームの回答を取得
  let items = event.response.getItemResponses()
  let values = {}
  for (var i = 0; i < items.length; i++) {
    values[items[i].getItem().getTitle()] = items[i].getResponse()
  }

  // プロパティ取得
  const key = PropertiesService.getScriptProperties().getProperty('NOTION_API_KEY');
  const databaseId = PropertiesService.getScriptProperties().getProperty('NOTION_DATABASE_ID');

  // Notionへリクエスト送信
  UrlFetchApp.fetch(
    "https://api.notion.com/v1/pages",
    {
      "method" : "POST",
      'headers': {
        'Authorization': 'Bearer ' + key,
        "Content-Type" : "application/json",
        "Notion-Version" : "2022-06-28",
      },
      "payload" : JSON.stringify({
        "parent": {
          "type": "database_id",
          "database_id": databaseId
        },
        "properties": {
          "Name": {
            "type": "title",
            "title": [
              {
                "type": "text",
                "text": {
                  "content": values['Name']
                }
              }
            ]
          }
        }
      })
    }
  )
}
```

- コードの処理の大まかな内容はこの３つです
    - 回答結果を取得
    - プロパティ情報(シークレットとdatabase_id)を取得
    - NotionAPIで送信

### プロパティ情報の設定

- プロパティ情報はGASページの左側にある歯車ボタンから設定できます
- 以下のスクリプトプロパティに設定することが出来るので、ここに値を保存しておきます。
![スクリーンショット 2023-12-16 21.53.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/65f32370-8b85-4ab1-2841-0505aa45478d.png)

### トリガーの設定

- 作ったコードを回答時に動かすにはトリガー設定をする必要があります
- トリガー設定は左側のメニューにあるトリガーから設定できます
![スクリーンショット 2023-12-16 22.44.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/55f71f2f-cdaa-88ff-7943-d0ccb65bc342.png)
- トリガーページを開いて右下にあるトリガー追加ボタンを押すと設定フォームが開きます
![スクリーンショット 2023-12-16 23.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/3d429d30-8ec1-b736-1625-528dfd5c9b84.png)
- ここで `イベントの種類を選択` をフォーム送信時にして、保存すれば完了です。


# 実行してみる

![スクリーンショット 2023-12-16 23.05.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/4d5a1908-9b87-06fe-c041-ff886423d0c9.png)
![スクリーンショット 2023-12-16 23.06.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240634/d143f6f1-be0d-ee6e-4453-8184f1565cf6.png)

ヨシ！！！

というわけで、回答結果をNotionに飛ばすことが出来ました。

# 感想

GASが思ったより簡単に使えたのがびっくりしました。
@hkusabaが社内でGAS記事を書いてたのを見てたので使ってみたいなーと思ってたので今回触れてよかったです。
console.logとかも普通に出せるのでjavascript書ける人はすぐかける。

NotionAPIについては最初に書いた通りなのですが、GoogleFormじゃなくてWEBサイトを作ったときの質問フォーム送信先にNotionにすれば管理画面作成を節約できて、質問のタスク管理できるのでは？とか色々用途がありそうです。

ということで以上になります。
突貫で書いたのでなにか変な記述あったらコメントしてもらえば