🔥

世界一簡単なCloud Functions For Firebase入門

2022/05/23に公開1

概要

これまで、自分はサーバーレス(AWS LamndaやCloud Functions For Firebase)という技術について触ったことがなく、どんなことができるかもいまいち知り得ないという状態でした。

そこで今回、軽く入門してみようと思い、簡易的なAPIの開発を通じて勉強していこうと思います。

今回のAPIの開発は専用のリポジトリを作成していますので、よかったら参考にしてみてください!
専用のリポジトリ

今回やることは、大まかに以下の通りです。

  1. firebaseのプロジェクトを新規開設
  2. 必要なライブラリをインストールし、セットアップを行う
  3. cloud functionsで何らかの値をレスポンスとして返してくれるエンドポイントを実装
  4. firebase deployする

上記の一連の流れとは別に、追加でfirestoreへのデータの追加・読み出しを行うAPIの実装なども行っていきたいと思ってます。

また、今後追加でfirestoreと連携させ、firestoreに格納されたデータなどをjson形式で返してくれるエンドポイントなんかも取り入れようと思っています。

コンソールからFirebaseのプロジェクトを作成する

プロジェクト名を決める

下記のプロジェクトを新規作成する画面で、何らかのプロジェクト名を入力して下さい。
今回、cloud functionのチュートリアルということで、自分はcloud-function-tutorialと名付けました。

名前の入力が完了したら、そのまま「続行」のボタンをクリックします。

Google Analyticsの設定をする

今回のプロジェクトではGoogle Analyticsを使用する予定はありませんので、有効のチェックを外していただいて大丈夫です。

最後に「プロジェクトを作成」するボタンをクリックいただくと、プロジェクトの作成が行われます。

下記のようにプロジェクトのダッシュボードの画面に遷移したら、無事プロジェクトの作成は完了です。

必要なライブラリ等のインストールおよびセットアップを行う

今回、cloud functionをいじる際に必要なライブラリや実行環境は下記の通りです。

  • Node.js
  • npm
  • firebase-tools

firebase-toolsというライブラリに関して

cliでfirebaseを使うのに必要になります。
こちらをインストールすることで、firebaseコマンドが使えるようになり、様々なことがcliでできるようになります。

今回は、npmNode.jsはインストール済みという前提で進めさせていただきます!🙇‍♂️

firebase-toolsをインストールする

下記のコマンドを実行して、firebase-toolsというライブラリをインストールします。

bash
$ npm install -g firebase-tools

下記のように、firebaseコマンドが実行できたらOKです。

bash
$ firebase --version
11.0.0

cliからfirebaseにログインする

クラウド上のfirebaseのアカウントとローカルのcli上のfirebaseとを紐づけるために、cliからfirebaseにログインします。

下記のコマンドでログインします。

bash
$ firebase login

※ログイン時に下記のような質問があると思いますが、n(No)でOKです!
これはただのFirebaseがCLIの使用状況とエラーレポート情報を収集できるようにするかどうかの確認なのでNoで大丈夫です。

bash
? Allow Firebase to collect CLI usage and error reporting information?

firebaseのプロジェクトの初期化を行う

bash
$ firebase init firestore
$ firebase init functions

上記の二つのコマンドを実行して、プロジェクトの初期化を行います。

この二つのコマンドをどちらも実行時にいくつかの質問に答えつつ、進めていってください。
基本的には、useing a exists project(文言あってなかったらごめんなさい)みたいなやつを選んでいただければOKです!

そちらを選ぶと、実際に既存のプロジェクトの中からどのプロジェクトを使用するか聞かれるので、先ほど作ったばかりのプロジェクトを選択してください。

またFunctionsの方では、Functionsに記述する言語をJavaScriptTypeScriptのどちらにするか質問されると思います。

今回のチュートリアルは、「世界一簡単」を目指していきたいのでJavaScriptを選択します。

上記の二つのコマンドの両方とも、下記のような文言が表示されれば初期化が無事完了したことになります。

bash
✔  Firebase initialization complete!

実際にAPIのエンドポイントを実装する

この段階で、ディレクトリ構成は下記のようになっています。

bash
$ tree .
.
├── .firebaserc
├── .gitignore
├── README.md
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
└── functions
    ├── .eslintrc.js
    ├── .gitignore
    ├── index.js
    └── package.json

このtree構造の中のfunctions/index.jsというファイルに実際のAPIのエンドポイントとなる関数を実装していきます。

今の時点では、functions/index.jsファイルは下記のようになっています。

functions/index.js
const functions = require("firebase-functions");

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
//   functions.logger.info("Hello logs!", {structuredData: true});
//   response.send("Hello from Firebase!");
// });

まずは、デフォルトで表記されているエンドポイントのサンプルコードを動かしてみたいと思います。
こちらのコメントになっている部分のコメントを外して下記のように書き換えます。

functions/index.js
const functions = require("firebase-functions");

// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions

exports.helloWorld = functions.https.onRequest((request, response) => {
  functions.logger.info("Hello logs!", {structuredData: true});
  response.send("Hello from Firebase!");
});

次にfunctionsディレクトリに移動し、firebaseのemulatorsを起動します。

bash
$ cd functions
$ npm run serve

下記のような画面になれば、無事起動完了です。

こちらのエンドポイントをcurlコマンドを叩いてみます。
helloWorldはfunctionの名前です。

bash
$ curl http://localhost:5001/${プロジェクトID}/${リージョン}/helloWorld

このコマンドの結果として、Hello from Firebase!という文字列が表示されれば成功です。

firebase deployする

一旦ここまでで、このfunctionをデプロイしてみたいと思います。

デプロイに際して、下記のコマンドを実行してください。

bash
$ firebase deploy --only functions

このコマンドを実行すると、下記のようなエラーメッセージが表示されるかと思います。

【Firebase】Cloud Functionsが従量課金プランでしか使えなくなるらしいというこちらの記事によると、どうやら

要約するとこんな感じ

  1. Cloud FunctionsがNode.js 10になってNode.js 8が非推奨になるよ
  2. いまNode.js 8使ってる人はアップデートしてね
  3. Node.js 10はBlaza(従量課金)プランでしか使えないからSpark(無料)プラン使ってる人はアップデートしてね
    ってことらしい

とのことらしいです。
ということで、コンソールからFunctionsのプランをSparkからBlazeにアップグレードしてください。

無料枠分はちゃんと適応されるぽいので、よっぽどのことがない限りはお金の支払いが発生することはないでしょう。

再度、上記のデプロイコマンドを実行してみてください。

bash
✔  Deploy complete!

このような文言が出力されれば、無事デプロイ完了です。

firestoreへのデータの追加・読み出しをするAPIを作ってみる

テストデータを用意する

今回は、まずIDがtestというcollectionを作成して、そのcollectionが存在していることを前提に進めていこうと思います。

※最初のこちらのcollectionと、初期データのに手動で作成いただくことになります。

初期データには、idフィールドとnameフィールドを作成して任意の値を設定してください。

admin sdkからfirestoreを使えるように設定する

functions/index.js
const admin = require("firebase-admin");

// Admin SDKでfireStoreを使う
admin.initializeApp(functions.config().firebase);

// データベースの参照を取得する
const fireStore = admin.firestore();

firestoreからデータを取得して返すエンドポイントを実装する

以下は実装は、firestoreのtestというcollectionから任意のdocument IDのドキュメントのデータを取得して、レスポンスとしてクライアントに返すというエンドポイントです。

functions/index.js
exports.getFirestore = functions.https.onRequest((req, res) => {
  // パラメータを取得
  const params = req.body;
  // パラメータから任意のdocument IDを取得する
  const documentId = params.documentId;

  if (documentId) {
    // 'test'というcollectionの中の任意のdocumentに格納されているデータを取得する
    const testRef = fireStore.collection('test');
    testRef.doc(documentId).get().then((doc) => {
      if (doc.exists) {
        res.status(200).send(doc.data());
      } else {
        res.status(200).send("document not found");
      }
    });
  } else {
    res.status(400).send({errorMessaage: 'document id not found'});
  }
});

以下のcurlコマンドを実行して、エンドポイントを確認してみてください。

bash
$ curl http://localhost:5001/${プロジェクトID}/${リージョン}/getFirestore --data 'documentId=${任意のdcument ID}'

firestoreのcollectionに任意のIDのドキュメントを作成するエンドポイントを実装する

以下の実装は、任意のデータ(パラメータ)を渡すとそれをfirestoreの任意のIDのdocumentを作成しデータを格納したのち、格納したデータをレスポンスとして返すというエンドポイントです。

functions/index.js
// 渡されたパラメータのスキーマをチェックする
const validateParamsSchema = (params) => {
  const hasId = 'id' in params;
  const hasName = 'name' in params;
  const hasDocumentId = 'documentId' in params;

  return hasId && hasName && hasDocumentId;
};

// firestoreに任意のデータを保存する
exports.saveFirestore = functions.https.onRequest((req, res) => {
  const params = req.body;
  // パラメータのスキーマのチェック
  if (!validateParamsSchema(params)) {
    res.status(400).send({errorMessaage: 'パラメータが不正です'});
  } else {
    const db = fireStore;
    // 'test'というcollectionがある前提で任意のドキュメントIDのdocumentを生成する
    db.doc(`test/${params.documentId}`).set({
      id: params.id,
      name: params.name,
    });

    // 非同期的に保存したデータを参照する
    db.collection('test')
        .doc(params.documentId)
        .onSnapshot((doc) => {
	  // 取得したデータをレスポンスとして返す
          res.status(200).send(doc.data());
        });
  }
});

こちらに関しても同様に、以下のコマンドでエンドポイントの確認をしてみてください。
各パラメータの値は任意の値でOKです。

bash
curl http://localhost:5001/${プロジェクトID}/${リージョン}/saveFirestore --data 'id=7&name=test 7&documentId=custome doc7'

再度、firebaseをdeployする

下記のコマンドを実行して、firestoreとcloud functionsをdeployします。

bash
$ firebase deploy --only functions
$ firebase deploy --only firestore

deployが成功したら、以上で本チュートリアルは終了になります。
お疲れ様でした。

何か不明点などがあればコメントを頂けますと幸いです。

参考サイト情報

Discussion

puddingpudding

記事を拝見させていただきました。
初心者の僕でもdeployを成功させることができました。
いろいろ調べてみたのですが、わからないことがいくつかあったので質問させていただきます。

  1. npm run serveのコマンド実行後
    npm run serveのコマンド実行後
    curl http://localhost:5001///saveFirestore --data 'id=7&name=test%207&documentId=custom%20doc7'
    と打ってみたのですが、エンターを押しても反応がなく(ただ改行されるだけ)、テスト試行ができませんでした。npm run serveの扱いについて調べてみたのですが、有益な情報は得られませんでした。

  2. jsコードの実行タイミング
    jsコードを使ってfirestoreの情報を更新したり、取得することが可能なのはわかりましたが、問題はjsファイルをdeployした後、どのタイミングでコードが実行されるのかということです。deploy直後に一度だけ実行されるのでしょうか?

素人質問で誠に恐縮ですが、返信くださると大変助かります。