Googleフォームの問合せをSlackに自動で通知してみよう

所要時間:60分

このレッスンのゴール

このレッスンでは、Googleフォームから、問い合わせがあった時にその結果をSlackに通知する方法を学びます。 完成すると、以下のような通知Botが起動して、フォームの内容を共有してくれます。

file

Googleフォームと、Slackを連携できると例えば、

  • ライターさんが入稿を完了したときに報告するフォームの内容を、Slack通知する
  • 入社書類の送信完了を、人事側で確認する

など、いろいろな用途に応用することが可能です。

このレッスンでできるようになること

このレッスンのプログラムを完成させることで、以下のことができるようになります。

  • Googleフォームの送信をトリガーにGoogleAppsScriptを実行できる
  • GoogleAppsScriptでGoogleフォームの情報を取得できる
  • GoogleAppsScriptでメッセージをSlackへ通知できる

レッスン開始前のチェックリスト

このレッスンを始める前に、次に当てはまる方は、このレッスンを受講する前に必要な準備を終わらせましょう!

  • Google Apps Scriptという用語を聞いたことがない
    →前のレッスン「Google Apps Scriptとは?」をまずは受講しましょう
  • JavaScriptを書いたことがない
    →まずはProgateでJavasrciptの基本を学びましょう
  • Googleのアカウントを持っていない
    →GASの利用にはGoogleアカウントが必要です。こちらからアカウント作成をしましょう
  • SlackのIncoming Webhookを使ったことがない
    →前のチュートリアル「Google Apps Script実践①」をまずは受講しましょう

このレッスンの流れ

それでははじめていきたいと思います。手順としては、以下のようになります。

  1. Slackの設定情報を定義する
  2. Googleフォームをトリガーに設定する
  3. Googleフォームの情報を受取る関数を実装する
  4. Slackにメッセージを送る関数を実装する

内容に入る前に、2つ事前準備があるのでそちらの設定をしていきましょう。

事前準備その1:Googleフォームを用意する

今回はGoogleフォームからの通知を、Slackへ送付するプログラムを作るので、Googleフォームをまずは用意する必要があります。 Google Driveにアクセスして、スプレッドシートを作成してください。

※すでに、Googleアカウントが存在する場合は、URLにspreadsheet.newと入力すると、新規でスプレッドシートを作成することができます。 [無題のスプレッドシート]という名前になっているので、「問い合わせフォーム」という名前に変更しておきましょう。

次に、Google Spreadsheetの[ツール] > [フォーム作成]をクリックします。

フォームを作成したら、適当な質問を設定しておきましょう。
下記の画像では具体例を示しています。参考にしてみてください。

  • 名前:記述式
  • メールアドレス:記述式
  • 質問内容:段落

次にGoogleフォームから、GoogleAppsScriptのエディタを開きましょう。

新規で作成すると、「無題のプロジェクト」となっているはずなので、[問い合わせスクリプト]に変更しておきましょう。 スクリプトエディアは、Google Apps Scriptを起動するためのツールです。

事前準備その2:SlackチャンネルとIncoming Webhookを用意する

次に、Slackチャンネルと、Incoming Webhookの設定をしましょう。Incoming Webhookとは、外部からSlackにデータを送った時に、そのデータを受け取るWebhookURLを取得するアプリのことです。

次の手順で取得できます。詳細はこちらのレッスンで画像付で流れを解説していますので、ご覧ください。

  1. SlackをWEBブラウザで開いて、画面右上の歯車のマークから、アプリを追加するを選ぶ
  2. 検索窓にincomingを入力し、Incoming Webhookアプリを選択する
  3. 設定を追加をクリックする
  4. チャンネルを選び、Incoming Webhookインテグレーションの追加をクリックする
  5. WebhookURLをコピーする

※注意:Incoming Webhookは、Slackの管理者、開発者権限がないと、利用することができません。会社で利用する場合、権限の関係でできない可能性があります。

これで事前準備は完了です!それではプログラムを実装していきましょう。

プログラムの全体像を確認しよう

それでは、さっそく実装していきましょう。 最終的なコードはこちらになります。
今すぐ全てが理解できなくて大丈夫です。詳細はこれから説明していきますので、ざっと全体を眺めておきましょう。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXX"

function onFormSubmit(e){
   let body = "";
   const itemResponses = e.response.getItemResponses();
   for (const index in itemResponses){
      const itemResponse = itemResponses[index];
      const title = itemResponse.getItem().getTitle();
      const response = itemResponse.getResponse();
      body += Utilities.formatString(title + ":" + response + "\n\n");
   }
   sendToSlack(body);
}

function sendToSlack(body) {
   const data = {
      "channel" : CHANNEL,
      "text" : body,
      "username" : "お問い合わせ通知",
      "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data);
   const options = {
      "method" : "POST",
      "contentType" : "application/json",
      "payload" : payload
   };
   UrlFetchApp.fetch(WEBHOOL_URL, options);
}

このコードは、大きく2つの関数に分かれています。

  1. Google フォームからデータを受け取るonFormSubmit関数
  2. Slackにデータを送信するsendToSlack関数

この後詳細を説明していきます。一緒に頑張りましょう!

Step1. Slackの設定情報を定義しよう

最初に通知するSlackのチャンネル名と、Webhook URLを定義します。
WebhookURLには事前準備で取得した内容をコピーペーストしましょう

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXX"

 

Step2. Googleフォームをトリガーに設定しよう

次にGoogleフォームが送信されたときに、関数が実行されるようにトリガーを設定しましょう。
最初にonFormSubmit関数を定義しておきます。実際の処理は次のステップで実装します。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXX"

function onFormSubmit(e){
}
e

次にトリガーを設定します。 トリガーとは、「こんな時に、こういう処理をしてね!」という設定を行うことができる機能です。

  • IF : もし~したら
  • THEN: ~する

の、IFにあたる部分と、THENにあたる部分を設定できます。今回は、

  • IF: フォームが送信されたときに
  • THEN: Slack通知する関数を起動する

というアクションになります。 それではさっそく設定していきましょう。下記の画像に沿って設定してみましょう。
トリガーは次のように設定します。

  • イベントのソースを選択:フォームから
  • イベントの種類を選択:フォーム送信時

[保存]をクリックすると、Googleアカウントに許可を出す画面が出てくるので、案内に従って承認をしてください。
これでStep1が完了です。

Step3. Googleフォームの情報を受取る関数を実装しよう

それでは、onFormSubmit関数を実装します。コードの中身は以下のようになっています。
一つひとつ詳細を見ていきましょう。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXX"

function onFormSubmit(e){
   let body = "";
   const itemResponses = e.response.getItemResponses();
   for (const index in itemResponses){
      const itemResponse = itemResponses[index];
      const title = itemResponse.getItem().getTitle();
      const response = itemResponse.getResponse();
      body += Utilities.formatString(title + ":" + response + "\n\n");
   }
   sendToSlack(body);
}

onFormSubmit関数を設定する

function onFormSubmit(e){
}

まず事前にセットしておいた、onFormSubmit関数は、実はGoogle Apps Script上で事前に用意されている関数(組み込み関数)です。フォームが送信されたときに、起動される関数で、引数のeには、フォームの申込情報が入るようになっています。

こちらのリンクで関数の説明が見れますので、一度見てみてください。英語ですが、プログラミングの学習にAPIのライブラリ情報を見るのは重要なので、ぜひ挑戦してみましょう。
https://developers.google.com/apps-script/reference/script/form-trigger-builder#onformsubmit

ログを残して、データを受け取れているか確認する

それでは試しに関数を起動させて、情報が受け取れているか確認してみましょう。
上記のコードに、ログを残すことで、実行されたか確認してみます。

まずは確認するために、console.log(e)を追記します。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXX"

function onFormSubmit(e){
   console.log (e); //1 ログを残すために、console.logで出力します
}

Google Formから試しに回答を一度送ってみましょう。
先ほど作成したGoogleフォームの送信 をクリックし、フォームの回答URLへアクセスして、適当な内容で回答を送信しましょう。

Google Apps Scriptでログを確認する場合は、[実行数]を選びましょう。トリガーで起動したonFormSubmit関数がきちんと動いていることが確認できたら、成功です!

フォームの内容を取得する

次に、フォームの内容を取得するための処理を書いていきたいと思います。
先ほど追加した、console.log(e)は確認用のコードなので削除して、続きを書いていきます。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXX"

function onFormSubmit(e){
   let body = "";
}

 まずSlackに通知するメッセージを格納する、bodyという変数を定義します。
letにしている理由は、今後再代入して、メッセージを追加していくためです。constを利用してしまうと、値を再代入できません。

getItemResponses関数の値の中身を取得する

次に、Googleフォームから受け取った情報を、どうやって確認するか見てみましょう。

Google Formから受け取った情報はFormResponseオブジェクトとして、e.responseで取得することができます。
そのFormResponseオブジェクトに対して、getItemResponses関数を実行することで、中身を取得することができます。

const CHANNEL = "contact"
const WEBHOOL_URL = const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"

function onFormSubmit(e){
   let body = "";
   const itemResponses = e.response.getItemResponses();
}

取得したitemResponsesは、次のような構成になっています。
itemResponsesの中には、title(質問文)とresponse(その回答)から構成されるitemResponseがたくさん入っている、という構成です。itemResponsesが取得できたら、今度はそこからitemResponseを取り出し、更にそこからtitleとresponseをそれぞれ取得する、という流れになります。

詳細を見ていく前に、一度Google Formの公式APIドキュメントを見てみましょう。
Class FormResponse

file

日本語に翻訳すると、以下のように書いてあります。

フォーム全体に対するレスポンス。FormResponse は 3 つの方法で使用することができます: 回答者によって提出された回答にアクセスする (getItemResponses() を参照)、プログラムによってフォームに回答を送信する (withItemResponse(response) と submit() を参照)、そして提供された回答を使ってフィールドをプリフィルするフォームの URL を生成することです。FormResponses はフォームから作成したりアクセスしたりすることができます。

リファレンスにあるサンプルコードを見てみます。
このコードを参考に、質問と回答を取得していきます。

// Open a form by ID and log the responses to each question.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
var formResponses = form.getResponses();
for (var i = 0; i < formResponses.length; i++) {
  var formResponse = formResponses[i];
  var itemResponses = formResponse.getItemResponses();
  for (var j = 0; j < itemResponses.length; j++) {
    var itemResponse = itemResponses[j];
    Logger.log('Response #%s to the question "%s" was "%s"',
        (i + 1).toString(),
        itemResponse.getItem().getTitle(),
        itemResponse.getResponse());
  }
}

 

itemResponsesオブジェクトから、itemResponseを取り出す

さて、それではitemResponseのリストであるitemResponsesが現在取得できているので、これからそれぞれの回答を取得していきます。
リストから一つずつ値を展開する場合は、for inを利用します。

const CHANNEL = "contact"
const WEBHOOL_URL = const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"

function onFormSubmit(e){ 
   let body = ""; 
     const itemResponses = e.response.getItemResponses(); 
     for (const index in itemResponses){ 
        //取得したitemResponsesを、一つずつfor文で書き出す } 
    }
}

複数のリストオブジェクトに対して、インデックス番号を指定してあげると、中身のオブジェクトを取得することができます。 それでは、次に質問内容を取得してみましょう。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"

function onFormSubmit(e){ 
   let body = ""; 
     const itemResponses = e.response.getItemResponses(); 
     for (const index in itemResponses){ 
       const itemResponse = itemResponses[index];
    }
}

 

質問と回答を取得する

次に質問と答えのセットとなったitemResponseオブジェクトから、質問内容のタイトルと回答を取得します。
それぞれ、getTitle()とgetResponse()という関数を使って取得できます。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"

function onFormSubmit(e){ 
   let body = ""; 
     const itemResponses = e.response.getItemResponses(); 
     for (const index in itemResponses){ 
       const itemResponse = itemResponses[index];
             const title = itemResponse.getItem().getTitle(); //質問と答えのセットとなったitemResponseオブジェクトから、質問内容のタイトルを取得する
             const response = itemResponse.getResponse(); //質問と答えのセットとなったitemResponseオブジェクトからgetResponse関数で答えを出力する
    }
}

Slackに送信するテキストの内容を作成する

これでGoogleフォームの質問と回答を取得できました。
それではこのステップの最後に、Slackに送信するためのテキストの内容を作成しましょう。
内容はシンプルで、最初に定義しておいたbodyに、取得したtitleとresponseを追加するだけです。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"​​​​​​​


function onFormSubmit(e){ 
   let body = ""; 
     const itemResponses = e.response.getItemResponses(); 
     for (const index in itemResponses){ 
       const itemResponse = itemResponses[index];
             const title = itemResponse.getItem().getTitle(); //質問と答えのセットとなったitemResponseオブジェクトから、質問内容のタイトルを取得する
             const response = itemResponse.getResponse(); //質問と答えのセットとなったitemResponseオブジェクトからgetResponse関数で答えを出力する
             body += title + ":" + response + "\n\n";
    }
}

 

Slackに送信する関数を先に定義しておく

それでは、次のステップで作るSlackにメッセージを送るための関数、sendToSlack()関数を最後に呼び出すコードを追記します。
sendToSlack関数は、先ほど作成したbodyを引数にして呼び出します。

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXXXXX"​​​​​​​


function onFormSubmit(e){ 
   let body = ""; 
   const itemResponses = e.response.getItemResponses(); 
   for (const index in itemResponses){ 
       const itemResponse = itemResponses[index];
       const title = itemResponse.getItem().getTitle(); //質問と答えのセットとなったitemResponseオブジェクトから、質問内容のタイトルを取得する
       const response = itemResponse.getResponse(); //質問と答えのセットとなったitemResponseオブジェクトからgetResponse関数で答えを出力する
       body += title + ":" + response + "\n\n";
   }
   sendToSlack(body);
}

これでこのステップが完了です!次はいよいよsendToSlack関数を実装していきます。

Step4. Slackにメッセージを送る関数を実装する

このステップでは、Slackにメッセージを送るsendToSlack()関数を実装します。
最終的には次のようなコードになります。

function sendToSlack(body) { 
   const data = {
       "channel" : CHANNEL,
       "text" : body,
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
   const options = { 
      "method" : "POST", 
      "contentType" : "application/json", 
      "payload" : payload 
  }; 
  UrlFetchApp.fetch(WEBHOOL_URL, options);
}
コード全体

順番にコードを解説していきたいところなのですが、その前に、まずはGoogleフォームと連携せず「test」とだけSlackにメッセージを送る仕様で実装してみましょう。実際にメッセージが送れることを確認したら、送信内容を送りたいメッセージに変更していきます。

では順番に解説していきます。

sendToSlack関数を定義する

まずは関数を定義します。見た目がシンプルになるように、前のステップで作った部分は今回は写していません。コードの下に追記していきましょう。

function sendToSlack(){

}

JSONで送信したい内容を連想配列形式で設定しよう

次に、メッセージの内容や、送付先のチャンネル名、ユーザー名やアイコンなどを設定します。
今回は変数dataの中に、連想配列形式で、データをセットします。ここで入れる値はテスト用なので、実装が確認できたら後から変更します。

function sendToSlack() { 
   const data = {
       "channel" : "contact",
       "text" : "test",
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
}

この設定では、下記のように表示されるはずです。

  • チャンネル名:contact
  • 送付されるメッセージ:test
  • ユーザネーム:お問合せ通知
  • アイコン:鳩のアイコン

連想配列をJSON化しよう

次に、Slack Web APIで利用できるJSON形式に、連想配列dataを変更します。
ここではJSON.stringify()という関数を利用します。

function sendToSlack() { 
   const data = {
       "channel" : "contact",
       "text" : "test",
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
}

 

Optionを設定しよう

次にSlackへメッセージを送るために必要な値をOptionで指定します。指定するのは、method、contentType、payloadの3つです。

function sendToSlack() { 
   const data = {
       "channel" : "contact",
       "text" : "test",
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
   const options = { 
      "method" : "POST", 
      "contentType" : "application/json", 
      "payload" : payload 
  }; 
}

URLFetchApp.fetch()を使ってSlackへ送信する

では最後に設定した内容を、取得しておいたWEBHOOK_URLを利用して送付しましょう。

function sendToSlack() { 
   const data = {
       "channel" : "contact",
       "text" : "test",
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
   const options = { 
      "method" : "POST", 
      "contentType" : "application/json", 
      "payload" : payload 
  }; 
   const response = UrlFetchApp.fetch(WEBHOOK_URL, options); 
}

ここまで設定できたら、実行してみましょう。今回はテスト用に、sendToSlack関数だけで実行できるようにしてあるので、GoogleAppsScriptのエディタから、実行する関数を「sendToSlack」に変更してから実行ボタンを押しましょう。

実行すると、許可が求められるので、指示に従って権限を許可してください。
指定したSlackのチャンネルに、鳩から画像のようにメッセージがくれば成功です!

Googleフォームの回答をSlackに送る仕様を実装する

それでは最後に、Googleフォームの回答内容をSlackに送る仕様に、sendToSlack関数を変更しましょう。
変更した箇所は3箇所です。

  1. sendToSlack関数の引数にbodyを追加する
  2. "channel"の値を、コードの最初で定義した変数CHANNELに変更する
  3. "text"の値を、引数に入れたbodyに変更する
function sendToSlack(body) { 
   const data = {
       "channel" : CHANNEL,
       "text" : body,
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
   const options = { 
      "method" : "POST", 
      "contentType" : "application/json", 
      "payload" : payload 
  }; 
   const response = UrlFetchApp.fetch(WEBHOOK_URL, options); 
}

これで完成!と言いたいところなのですが、もう一つだけやることがあります。
Google Apps Scriptでは、Slackなど他のアプリと連携をする際には、実行の許可をする必要があります。今回はGoogleAppsScriptからSlackへの通知は許可しているのですが、別途Googleフォームの情報を外部アプリに通知を出す際にも許可が必要です。

そこで、事前に作成していた、onFormSubmitにFormApp.getActiveForm();を追記して、GoogleAppsScriptエディタから一度関数を実行しておきます。実行する関数を「onFormSubmit」に変更してから実行ボタンを押しましょう。うまくいっていれば許可を求められるので、許可をして、追加した行を削除します。

function onFormSubmit(e){
   FormApp.getActiveForm(); //許可を与えるために追加した行
   let body = "";
   const itemResponses = e.response.getItemResponses();
   for (const index in itemResponses){
      const itemResponse = itemResponses[index];
      const title = itemResponse.getItem().getTitle();
      const response = itemResponse.getResponse();
      body += Utilities.formatString(title + ":" + response + "\n\n");
   }
   sendToSlack(body);
}

お疲れ様でした、これで完成です!

最後に全体のプログラムを確認してみましょう。 

const CHANNEL = "contact"
const WEBHOOL_URL = "https://hooks.slack.com/services/XXXXXXXXXXXX"

function onFormSubmit(e){
   let body = "";
   const itemResponses = e.response.getItemResponses();
   for (const index in itemResponses){
      const itemResponse = itemResponses[index];
      const title = itemResponse.getItem().getTitle();
      const response = itemResponse.getResponse();
      body += Utilities.formatString(title + ":" + response + "\n\n");
   }
   sendToSlack(body);
}


function sendToSlack(body) { 
   const data = {
       "channel" : CHANNEL,
       "text" : body,
       "username" : "お問い合わせ通知",
       "icon_url" : "https://4.bp.blogspot.com/-mfqbB0DfCDo/UTbWrZXNlPI/AAAAAAAAOic/lkRI5dseik4/s400/bird_hato.png"
   };
   const payload = JSON.stringify(data); 
   const options = { 
      "method" : "POST", 
      "contentType" : "application/json", 
      "payload" : payload 
  }; 
  UrlFetchApp.fetch(WEBHOOL_URL, options);
}

それでは動作テストをしてみましょう。 Apps Scriptエディタを起動して、ログを見れる状態にしたまま、Google Formを送信してみましょう。 うまくいくと、contactというチャンネルに、メッセージが送信されます。