Firebaseで作るWebアプリケーション - データベースにデータを保存する


今回やること

前回は、WebブラウザのクライアントからAPIを呼び出す処理を作成しました。

今回は、データベース(Firestore)へデータを保存する処理を作成します。

データベースへのデータの保存

Firestoreは、キーバリュー型のデータベースです。指定のキーに紐付けて、データを保存することができます。例えば郵便番号をキーに、住所をデータとして保存する、というようなイメージです。

次のように記述することでデータを保存できます。

admin.firestore().collection('addresses').doc('100-0001').set({
  address: '東京都千代田区千代田1番1号',
});

collectionsの引数にはコレクション名を指定します。データの種類のようなもので、好きに設定することができます。RDBでのテーブル名に相当します。

docの引数にデータのキーを指定します。setの引数にデータの本体を指定します。ここでは、郵便番号をキーに住所データを設定しています。

APIからデータベースにデータを保存する

APIが呼び出されたときにデータを保存するように、APIを記述します。

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

admin.initializeApp();

export const createArticle = functions.https.onCall(async (data, context) => {
  await admin.firestore().collection('articles').doc().set({
    body: 'Article!!',
  });
});

admin.initializeApp()はadminモジュールの初期化処理で、使用前に呼び出しておく必要があります。

「admin使ってFirestoreにアクセスしていいの?」と思うかもしれませんが、APIからはadminでアクセスするしか手段がありません。

adminを使用すると、Firestoreへのアクセス権限を全て無視してデータを取得することができます。環境構築時に「設定されたアクセス以外を全て拒否する」に設定し、まだ何も設定していない状態のため、全てのアクセスが拒否されるという設定状態ですが、adminからなのでアクセスできます。

(APIからのFirestoreへのアクセスに制限をかけたい場合は、API自体の呼び出しを制限しろ、というFirebaseの方針なのではないかと思われます)

ここではcreateArticleというAPIを作成し、コレクションarticles

{
  body: 'Article!!',
}

というデータを追加しています。

キーを指定していませんが、指定しなかった場合は重複しない一意なIDが自動で指定されます。

クライアントからAPIを呼び出す

ボタンを用意して、押された場合にAPIが呼び出されるようにします。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>cmnty2020</title>

    <!-- update the version number as needed -->
    <script defer src="/__/firebase/7.15.0/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="/__/firebase/7.15.0/firebase-auth.js"></script>
    <script defer src="/__/firebase/7.15.0/firebase-database.js"></script>
    <script defer src="/__/firebase/7.15.0/firebase-messaging.js"></script>
    <script defer src="/__/firebase/7.15.0/firebase-storage.js"></script>
    <script defer src="/__/firebase/7.15.0/firebase-functions.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script defer src="/__/firebase/init.js"></script>
  </head>

  <body>
    <div id="app">
       <button v-on:click="createArticle">データ追加</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function() {
        new Vue({
          el: "#app",
          methods: {
            createArticle: async function () {
              await firebase.functions().httpsCallable('createArticle')();
            }
          },
        });
      });
    </script>
  </body>
</html>

ボタンが押された際に

await firebase.functions().httpsCallable('createArticle')();

を呼び出しているだけです。

$ firebase deploy

でアップロードしてブラウザで開き、ボタンを押すとFirestoreにデータが保存されます。

ボタンを押した後にFirebaseの管理画面でデータベースのところを見ると、

このようにデータが保存されています。

注意 !!

APIにアクセス制限をかけていないため、誰かにボタンを連打されると無限にデータが入り続けます。Firebaseは有料のサービスのため、無限にデータを入れられると無限に費用が発生してしまいます。

もし上述のコードを試した人がいたら、試し終わった時にAPIを削除しておきましょう。関数を消して$ firebase deployすれば、APIを削除することができます。

続く...