今Googleで最も熱いサービスFirebaseで、リアルタイムWebアプリをサクッと作ってみた

みなさん、ごきげんよう。プレイドの@akobaです。
プレイドではCXチームのエンジニアとして、プロダクトの機能開発、ならびに弊社のウェブ接客プラットフォームKARTEで提供するアプリケーションの開発を行っています。
今回は、KARTEでできることを広げる試みの一環として、Firebaseというサービスを使ってWebサイト上で動作するアプリケーションをいくつか作ってみたのでご紹介します。
具体的には、ユーザーの閲覧履歴、レビュー/コメント機能、今この記事をxx人が見ていますといった機能を作ってみました。
通常ネイティブアプリ向けとして使われることが多いFirebaseですが、Webブラウザ上でも色々と面白いことができます。
この記事が皆さんの開発の参考になれば幸いです。

目次

  • Firebaseとは
  • Firebaseにデータを貯めていく
  • ページ内でユーザーの情報を共有する
  • リアルタイム機能を使う
  • KARTEを使ってアプリを配信
  • まとめ

Firebaseとは

Firebaseとは、最近大きく注目を集めているMBaaS(Mobile Backend as a Service)、つまりモバイル開発のためのクラウド・ベースのバックエンドサービスです。2014年にGoogleに買収され、Google I/O 2016で新バージョンが発表されました。
ここでのバックエンドとはDB、認証、ストレージ、解析、メッセージングプラットフォームなど(詳細は公式サイト参照)で、主にネイティブアプリ向けのプラットフォームとして提供されています。
ただし、Web用のSDKも準備されており、今回はこのSDKをWebサイト上で使ってみたいと思います。

SDKといっても、Webページに下記のようなタグを貼るだけです。
web-setup-code
(xxxの箇所はFirebaseのプロジェクトによって異なります。詳細はこちら

Firebaseには様々な機能が用意されていますが、今回はRealtime Database機能にフォーカスして使ってみます。
この機能、BaaSなので当然なのですが、自分でサーバーを立てる必要がなく、上記のタグを貼るだけでブラウザからアクセス可能なKVSとして利用できます。
DBとしての特徴は主に下記となります。

  1. DB全体が1つのJSON treeとして扱える
  2. データの更新時、データを使っている各クライアントにリアルタイムで同期される
  3. オフライン時もクライアント側でデータを保持し、オンラインになった時点でオンラインデータとマージされる

1のために、個別のデータを更新するにはそのパスを指定して更新、全体を更新するにはルートパスに大きなJSONを1つ送るだけで済みます。(ただし大きすぎるJSONについてはそのまま送信はできないので、細かく分割して送信するツールが公開されています。)また読み込みの際も、全体のデータが欲しいのか、一部のデータが欲しいのかを、参照するJSONのパスを指定することで細かく指定することができます。
2は色々と面白いことができそうですね。
3もかなり便利そうですが、今回は使いません。

Firebaseにデータを貯めていく

では、実際にFirebaseのDBを使ってみましょう。

FirebaseのDBはKVS(Key Value Store)なので、なんらかのキーを軸にデータを集めていくことになります。
キーとして もっともよく使われるのはユーザーID(ユーザー軸)でしょう。それ以外にWebページのURLやWebページ上のアイテム・コンテンツID、もしくは地域やユーザー属性のようなものをキーにしても面白いかもしれません。
今回は、ユーザー軸とWebページ軸の情報をFirebaseに集めることにします。

まず最初にWebページ軸の情報。

var pagePath = 'page/' + encodeURIComponent(location.pathname).replace(/\./g, '%2E');
firebase.database().ref(pagePath)
  .set({
    image: image,
    title: title
  });

ページのURLパスをキーとして、ページ毎に、そのページのタイトルと画像URLを保存してみます。Open Graphの値などを入れておくといいですね。
page/の部分はなんでもいいですが、RDBのテーブル名のように、データの種類を区別するためにつけておきます。また、Firebaseのキー名には., $, #, [, ], /は使えないのでパーセントエンコードしておきます。(が、以下では簡略化のためにエンコードのコードは記載しません)

次にユーザー軸の情報。単純に、閲覧したページのURLを保存しておきましょう。

var userPath = 'user/' + userId;
firebase.database().ref(userPath + '/visit/' + location.pathname)
  .set({
    timestamp: parseInt(new Date() / 1000)
  });

ごちゃっとしていますが、user/[ユーザーID]/visit/[URLパス]timestampという値を書き込んでいます。
userIdの箇所は、なんらかの形で保持しているユーザー毎のIDを使用します。

ユーザーがページを見るたびにその情報をFirebaseに書き込んでいくと、FirebaseのDBには下記のようにデータが溜まっていきます。

{
  "page" : {
    "%2Fproducts%2Fdetail%2F12" : {
      "image" : "http://xxx.jpg",
      "title" : "xxx"
    },
    ...
  },
  "user" : {
    "akoba" : {
      "visit" : {
        "%2Fproducts%2Fdetail%2F12" : {
          "timestamp" : 1474968518
        }
      }
    },
    ...
  }
}

こうやって、ユーザー毎にそのユーザーが見たページのURL(パス)、ページ毎にそのページのタイトルと画像を保存しておくと、最近見たページのリスト(いわゆる閲覧履歴)が表示できます。

まず最初に、自分のユーザー情報を取得します。

firebase.database().ref(userPath)
  .once('value')
  .then(function(snapshot) {
    var myUserData = snapshot.val();
    ...
  });

onceとは、このタイミングでデータを一度だけ取得するということです。更新の監視は行いません。

myUserDataには上記のJSONの一部、下記のようなデータが入っています。

"visit" : {
  "%2Fproducts%2Fdetail%2F12" : {
    "timestamp" : 1474968518
  }
}

このvisit以下の各キーについて、ページの情報を取得すると、過去閲覧したページの画像とタイトルを表示できます。

recent_items

1点注意ですが、当然閲覧履歴はどんどん溜まっていきます。残念ながら、現状FirebaseのDBにはexpireの機能がないようなので、ある程度の数を超えたらtimastampの古いものから消していく等の対応が必要です。

ページ内でユーザーの情報を共有する

先ほどの例は、ユーザーを軸に、ページの情報を取得しましたが、その逆も可能です。
たとえば、

firebase.database().ref(pagePath + '/review/' + userId)
  .set({
    nickname: nickname,
    comment: comment,
    starCount: starCount,
    timestamp: parseInt(new Date() /1000)
  });

のような値を書き込むことで、ページにユーザーレビューを投稿する機能も実装できます。
ユーザーレビューまで行かなくても、書き込みを例えばサイトのスタッフのみに制限しておけば、各ページ、そのページに表示されている商品や記事への、スタッフのコメント機能が実現できます。

staff_comment

スタッフは、実際に自分のサイトにアクセスして、該当のページでコメントを入力するだけです。
こういった機能はいかにもウェブ接客という感じですね。

リアルタイム機能を使う

Firebaseの特長でもある、リアルタイムのデータ同期機能を使ってみましょう。
今度もページ軸で、

firebase.database().ref(pagePath + '/visit/' + userId)
  .set({
    timestamp: parseInt(new Date() /1000)
  });

そのページを見ているユーザーをどんどんページ情報に追加していきます。
ページ側では、そのページの情報を下記のように取得します。

firebase.database().ref(pagePath + '/visit')
  .on('value', function(snapshot) {
    updateUserCount(snapshot.numChildren());
  });

先ほどのonceと違い、onでは対象の値が更新されるたびに都度、指定した関数が実行されます。numChildrenでデータ内の子要素の数を取得し、updateUserCountで表示するユーザー数の値を更新します。
こうしておくと、表示されているユーザー数が、新しくユーザーが来訪するたびに増えるようになります。

ということで、今このページに出ている↓は、実際にFirebaseで作っています。

なんか出てたけど消しちゃったよという方は、このページをリロードいただくともう一度出るかと思います。

こちらについても、timestampをチェックして一定時間以上前のユーザーは削除していく等の対応が必要です。このページに設置してあるものについては、ページの閲覧から10分以上経過したユーザーを削除しています。

KARTEを使ってアプリを配信

最後に、こうやって作ったアプリケーションを、弊社のウェブ接客プラットフォームKARTEで実際に配信してみます。
上記のサンプルでは、ユーザー軸、ページ軸ともFirebaseのDBを使ったのですが、KARTE自体がユーザー軸の解析を行っているので、ユーザー軸のデータの管理はKARTEに任せることができます。
したがって、KARTEを使って上記のアプリを配信する際は、下記のような役割分担となります。

  • KARTE:いつ・誰に・どうやって配信するかを制御。ユーザー情報を管理
  • Firebase:ページ毎の情報を管理

KARTEでは、通常あらかじめ用意されたテンプレートを利用し、色やテキスト、画像等を差し替えるだけでコンテンツが配信可能です。しかし、もちろんフルカスタマイズすることも可能で、HTML、CSSに加えてJavaScriptの実行も可能な自由度の高いプラットフォームとして作られています。
したがって、今回のような外部のサービスを利用することも、そのためにそのサービスのタグを呼び出すことも可能です。また、今回の記事では触れていませんが、いわゆるウィジェットを作る用のAPIも用意されています。

実際に作成しているエディタの画面です。

HTML、CSS、JavaScriptが自由に編集できるので、ここにFirebaseを使用するコードを書きます。

先ほどご紹介した、このページで表示しているユーザー数のカウンターも、KARTEを使って配信しています。

まとめ

最後は少し駆け足になってしまいましたが、Firebaseを使って簡単にWebサイト上で動作するリアルタイムアプリケーションが作れる様子、またそれをKARTEを使ってWebサイト上に自由に配信できる様子が伝わりましたでしょうか。
実際、Firebaseでアプリケーションを開発する際には、事前に用意する必要があるものもほとんどなく、思い立ったタイミングでサクッと簡単に機能を実装できてしまいます。

ウェブ接客プラットフォーム「KARTE」を運営するプレイドでは、KARTEを使ってこんなアプリケーションが作りたい! KARTE自体の開発に興味がある!というエンジニア(インターンも!)を募集しています。
詳しくはWantedlyをご覧ください。 もしくはお気軽に、下記の「話を聞きに行きたい」ボタンを押してください!