GAミント至上主義

Web Monomaniacal Developer.

Firestore + Cloud Functions + Hangouts Chatで簡易メッセージフォームを作る

yagish履歴書で、お問合せ用にGoogleフォームは設置しているけど、もっと気軽な問合せフォームみたいのを作りたい。

でも、メールで送るのも、受け取るのもちょっと面倒なので、チャットに来ればいいやと考えた。

Slackも使っているけど、会社でG Suiteを使っていることもあり、せっかくなのでHangouts Chatを使ってみることにした。

gsuite.google.co.jp


全体の流れとしては下記のような感じ。

1. Firebaseでログインしているユーザーがテキストフォームに書き込んで送信

2. Firestoreの新規ドキュメントに問い合わせ内容を書き込む

3. Hangouts ChatのWEB Hook URLを取得。

4. FunctionsのonCreateで2を受け取ってChatのAPIにPOSTする。


1はyagish履歴書で出来ているので省く。ほんとはログインなしでも書き込みさせたいけど、スパム対策とユーザーごとのディレクトリで管理しているのでそれをそのまま使いたいため、ログイン必須にする。
またログイン必須にすると名前とかメールアドレスを入れなくていいので、メッセージ蘭だけになり、シンプルにできる利点も。

2. Firestoreへの書き込み

普通にaddする。
Cloud Firestore にデータを追加する  |  Firebase

以下疑似コード。
今後運営からお返事を書くかもしれないので、データにはユーザー情報も持たせておく。あと最新順に並び替えるようにtimestampも持たせておく。

const postCardData = {
  content: message,
  author: {
    uid: user.uid,
    email: user.email
  },
  timestamp: firebase.firestore.FieldValue.serverTimestamp()
}
// {uid}は仮、ちゃんと入れないとダメ
db.collection('/userdir/{uid}/postcards/').add(postCardData)

3. Hangouts ChatのWEB Hook URLを取得

チャットルームを作り、左上のところからつくれる。場所は分かりづらいけど、名前とオプションでアイコンを設定するだけで作れる。

f:id:uyamazak:20180918143237p:plain

4. FunctionsのonCreateで2を受け取ってChatのAPIにPOST

公式通り、Firebase Functions環境を準備する。
Firebase Cloud Functions  |  Firebase

Hangouts ChatのWEB Hookについては公式参照。
Using incoming webhooks  |  Hangouts Chat API  |  Google Developers

リクエストにはrequestを使った。
www.npmjs.com

jsonという専用パラメータで送るのが分からずしばらくハマった。
jsonにオブジェクトを入れるとstringifyして送ってくれる。

まだログもいろいろ出してて、完成じゃないけどコードは下記のような感じ。
本文を作るところは何かしらテンプレート的なものを使った方がよさそう。

const functions = require('firebase-functions');
const request = require('request');
// https://firebase.google.com/docs/functions/manage-functions?hl=ja
const runtimeOptions = {
  timeoutSeconds: 30,
  memory: '128MB'
}

const WEBHOOK_URL = "https://chat.googleapis.com/v1/spaces/XXXXXXXXXXXXXXXXXXXXXXX"

exports.sendPostCard2Chat = functions
  .runWith(runtimeOptions)
  .firestore
  .document('/userdir/{uId}/postcards/{postCardId}')
  .onCreate((snap, context) => {
      console.log('snap', snap)
      console.log('context', context)
      const val = snap.data();
      console.log('bodyText', bodyText)
      const options = {
        url: WEBHOOK_URL,
        headers: {
           'Content-Type': 'application/json; charset=UTF-8'
        },
        json: {text: 'email: ' + val.author.email + ' \n' + 'uid: ' + val.author.uid + ' \n' + 'site: ' + val.site + ' \n' +  'message:\n' + val.content}
      };
      request.post(options,
        (e, r, body) => {
          console.log('callback e:', e)
          console.log('callback r:', r)
          console.log('callback body:', body)
        }
      )
    });

ハマりどころとして、タイムアウトとか、メモリ、リージョンもこのコード上で指定できるが、リージョンを日本にしてしまうと動かなかった。
おそらくFirestoreがus-centralだからかなぁと思ったがよく調べてない。

これで、いまどきのサーバーレス&チャットで簡単なメッセージフォームができた。
データもチャットだけでなくFirestoreにも残せるので夢が広がる。

問題としてはこれだけのために普段使ってないHangouts Chatを開かねばいけないところ。

あと注意点としてFirestoreもFunctionsもβなので、大事なお問合せには使わない方がよさそう。