10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Firebase + TypeScript】Cloud Functionsについての備忘録

Last updated at Posted at 2021-12-26

概要

こちらの記事を購入して初めてCloud Functionsについて学んだ内容を備忘録として残しています

Cloud Functions for Firebaseとは

Cloud Functions for Firebase はサーバーレス フレームワークで、Firebase の機能と HTTPS リクエストによってトリガーされたイベントに応じて、バックエンド コードを自動的に実行できます。JavaScript または TypeScript コードは Google のクラウドに保存され、マネージド環境で実行されます。独自のサーバーを管理およびスケーリングする必要はありません。

環境構築

プロジェクトの作成

スクリーンショット 2021-12-26 1.40.30.png

Cloud Firestoreの作成

スクリーンショット 2021-12-26 1.43.35.png

Firebase CLI導入

npm install -g firebase-tools

プロジェクトディレクトリを作成

# 任意のプロジェクトディレクトリを作成
mkdir functions-test
cd functions-test

# プロジェクトを作成したGoogleアカウントでログイン
firebase login

Firebaseプロジェクトを初期化

/Document/functions-test
firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##      
     ######    ##  ########  ######   ########  #########  ######  ######  
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##      
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. 
 ( ) Database: Configure Firebase Realtime Database and deploy rules
 (*) Firestore: Deploy rules and create indexes for Firestore
 (*) Functions: Configure and deploy Cloud Functions
 ( ) Hosting: Configure and deploy Firebase Hosting sites
>(*) Storage: Deploy Cloud Storage security rules
 ( ) Emulators: Set up local emulators for Firebase features
 ( ) Remote Config: Get, deploy, and rollback configurations for Remote Config

? Please select an option: (Use arrow keys)
> Use an existing project 

Select a default Firebase project for this directory:
Firestore Setup

? What file should be used for Firestore Rules? (firestore.rules)
? What file should be used for Firestore indexes? (firestore.indexes.json)
? What language would you like to use to write Cloud Functions?
  JavaScript
> TypeScript

? Do you want to use ESLint to catch probable bugs and enforce style? (Y/n)
# 今回はESLintは導入しないので"n"

=== Storage Setup

? What file should be used for Storage Rules? (storage.rules)
+  Firebase initialization complete!

# コードを最新にする
npm install firebase-admin@latest firebase-functions@latest
npm install -g firebase-tools

403エラーが発生する場合は以下を参考にしてください

npmのアップデートを検証する

/Document/functions-test
# アップデート検証ツールをインストール
npm install -g npm-check-updates

# 検証開始
ncu

# package.jsonをアップデート
ncu -u

# 最新バージョンをインストール
npm install

Cloud Functionsをデプロイする

サンプルメソッドのコメントアウトを解除する

functions/src/index.ts
import * as functions from "firebase-functions";

// Start writing Firebase Functions
// https://firebase.google.com/docs/functions/typescript

export const helloWorld = functions.https.onRequest((request, response) => {
  // FirebaseConsole(GUIの管理画面)のFunctionsにログを出力
  functions.logger.info("Hello logs!", { structuredData: true });
  // response.sendでリクエスト元に値を返す
  response.send("Hello from Firebase!");
});

Cloud Functions のデプロイをする

作成したプロジェクトを従量制に変更してください

/Document/functions-test
firebase deploy --only functions

デプロイ結果

スクリーンショット 2021-12-26 2.12.46.png
先ほどの関数の結果が画像のURLに表示されます
スクリーンショット 2021-12-26 2.13.11.png

Firebase Local Emulator Suiteの導入

Firebase Local Emulator Suite は、Cloud Firestore、Realtime Database、Cloud Storage、Authentication、Cloud Functions、Pub/Sub、Firebase Hosting を使用してアプリをローカルでビルドおよびテストするデベロッパー向けの高度なツールセットです。

/Document/functions-test
firebase init emulators

=== Emulators Setup
? Which Firebase emulators do you want to set up? Press Space to select emulators, then Enter to confirm your choices. 
 (*) Authentication Emulator
 (*) Functions Emulator
>(*) Firestore Emulator
 ( ) Database Emulator
 ( ) Hosting Emulator
 ( ) Pub/Sub Emulator
 (*) Storage Emulator
# -------------------------------------------------------------------------
# 上記のように選択してEnter
# -------------------------------------------------------------------------
? Which port do you want to use for the auth emulator? (9099)
? Which port do you want to use for the functions emulator? (5001)
? Which port do you want to use for the firestore emulator? (8080)
? Which port do you want to use for the storage emulator? 9199
# -------------------------------------------------------------------------
? Would you like to enable the Emulator UI? Yes
? Which port do you want to use for the Emulator UI (leave empty to use any available port)? 
? Would you like to download the emulators now? No
+  Firebase initialization complete!

ビルドする

/Document/functions-test
cd functions/
npm run build

エミュレーターを起動

/Document/functions-test
firebase emulators:start

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions      │ localhost:5001 │ http://localhost:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Storage        │ localhost:9199 │ http://localhost:4000/storage   │
└────────────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

スクリーンショット 2021-12-26 2.34.50.png

Cloud Firestoreにエクスポート・インポートする

保存(エクスポート)

/Document/functions-test/functions
firebase emulators:export ed

値をエミュレータに読み込む(インポート)

/Document/functions-test/functions
firebase emulators:start --import=ed

HTTPリクエストをトリガーに Cloud Firestore の値を返す

Cloud Firestore

Google の柔軟でスケーラブルな NoSQL クラウド データベースを使用して、クライアント側開発とサーバー側開発のデータを保存、同期します。

Cloud Firestore にデータを追加する

スクリーンショット 2021-12-26 19.20.43.png

Cloud Firestoreからデータを返却する処理を追加

functions/src/index.ts
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";

// firebase-adminを初期化
admin.initializeApp();

export const getBooks = functions.https.onRequest(async (request, response) => {
    try {
        // firestoreのインスタンスを取得
        const db = admin.firestore();

        //インスタンスからコレクションを取得
        const ref = await db.collection('books').get();
        response.send(ref.docs.map(book => book.data()));
    } catch (e) {
        console.error(e);
        response.status(500).send(e);
    }
});

ビルドする

/Document/functions-test/functions
npm run build

エミュレータ上のFirestoreにデータを追加

/Document/functions-test
firebase emulators:start

# 8080ポートが既に使用されているエラーが出る場合
firestore: Port 8080 is not open on localhost, could not start Firestore Emulator.
⚠  firestore: To select a different host/port, specify that host/port in a firebase.json config file:
      {
        // ...
        "emulators": {
          "firestore": {
            "host": "HOST",
            "port": "PORT"
          }
        }
      }
i  emulators: Shutting down emulators.

Error: Could not start Firestore Emulator, port taken.

# 8080ポートが何に使われているかを確認
sudo lsof -i:8080 
java    4190 xxxxx  147u  IPv6 0x372f84f782df4f69      0t0  TCP localhost:http-alt (LISTEN)

# プロセス終了
kill 4190

# 再度エミュレーターを起動する
firebase emulators:start

✔  functions[us-central1-getBooks]: http function initialized (http://localhost:5001/functions-test-6696a/us-central1/getBooks).

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4001/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions      │ localhost:5001 │ http://localhost:4001/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4001/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Storage        │ localhost:9199 │ http://localhost:4001/storage   │
└────────────────┴────────────────┴─────────────────────────────────┘

Firestoreにアクセスしコレクションを追加する

スクリーンショット 2021-12-26 21.02.00.png

Cloud Firestoreからデータを返却する処理を実行する

 curl http://localhost:5001/functions-test-6696a/us-central1/getBooks
[{"ins_ts":{"_seconds":1640519638,"_nanoseconds":801000000},"title":"CloudFunctions入門","price":1000}]%        

Cloud Firestore トリガー

Cloud Functions を使用すると、クライアント コードを更新することなく、Cloud Firestore 内のイベントを処理できます。Cloud Firestore の変更は、DocumentSnapshot インターフェースまたは Admin SDK を使用して行うことができます。

イベントタイプ トリガー
onCreate ドキュメントが最初に書き込まれたときにトリガーされます。
onUpdate すでに存在するドキュメントの値が変更されたときにトリガーされます。
onDelete データを含むドキュメントが削除されたときにトリガーされます。
onWrite onCreateonUpdate または onDelete がトリガーされたときにトリガーされます。

onCreate

functions/src/index.ts
// 以下を追加する

export const store = functions.https.onRequest(async (request, response) => {
    if (request.method !== 'POST') {
        response.status(400).send('【不正】リクエストタイプが不正です。');
    }

    const body = request.body;

    try {
        const db = admin.firestore()
        await db.collection('books').add({body})
        response.send("Complete")
    } catch (e) {
        console.error(e);
        response.status(500).send(e)
    }
});

export const onCreateByBook = functions.firestore.document('books/{isbn}').onCreate(async (snapshot, context) => {
        const storedData = snapshot.data();
        const isbn = context.params.isbn
        const title = storedData.body.title
        const price = storedData.body.price
        console.log(`【新着本追加】ISBN: ${isbn}, タイトル: ${title}, 価格: ${price}`);
    }
)

ビルド

/Document/functions-test/functions
npm run build

エミュレーターを起動する

/Document/functions-test/functions
firebase emulators:start
i  emulators: Starting emulators: auth, functions, firestore, storage
⚠  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: database, hosting, pubsub
⚠  Your requested "node" version "14" doesn't match your global version "12"
i  firestore: Firestore Emulator logging to firestore-debug.log
⚠  ui: Emulator UI unable to start on port 4000, starting on 4001 instead.
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/Users/habanaoki/Documents/study/functions-test/functions" for Cloud Functions...
✔  functions[us-central1-getBooks]: http function initialized (http://localhost:5001/functions-test-6696a/us-central1/getBooks).
✔  functions[us-central1-store]: http function initialized (http://localhost:5001/functions-test-6696a/us-central1/store).
✔  functions[us-central1-onCreateByBook]: firestore function initialized.

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4001                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4001/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions      │ localhost:5001 │ http://localhost:4001/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4001/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Storage        │ localhost:9199 │ http://localhost:4001/storage   │
└────────────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

登録処理

curl -X POST -H "Content-Type: application/json" -d '{"price":500,"title":"sample"}' http://localhost:5001/functions-test-6696a/us-central1/store

Firestore・FunctionsのURLにアクセスする

Firestoreに登録したデータが表示される

スクリーンショット 2021-12-26 23.22.07.png

oncreateをトリガーしてログを表示されていれば成功
スクリーンショット 2021-12-26 23.21.55.png

onUpdate

document()で指定したコレクションのドキュメントの更新をトリガーに関数が実行される。

functions/src/index.ts
// 以下を追加後ビルドします
export const onUpdateByBook = functions.firestore.document('books/{isbn}').onUpdate(async (change, context) => {
        const before = change.before.data()
        const after = change.after.data()
        console.log(`【変更前】: ${before.body.price}, [変更後]: ${after.body.price}`);
    }
)

FireStoreから任意のコレクションを更新します

スクリーンショット 2021-12-26 23.34.08.png

更新処理をトリガーできれば成功

スクリーンショット 2021-12-26 23.43.36.png

onDelete

document()で指定したコレクションからのドキュメントの削除をトリガーに関数が実行される。

functions/src/index.ts
// 以下を追加後ビルドします
exports.onDeleteByBook = functions.firestore.document('books/{isbn}').onDelete(async (snapshot, context) => {
    const data = snapshot.data()
    const isbn = context.params.isbn
    const title = data.body.title
    const price = data.body.price
    console.log(`【削除】ISBN: ${isbn}, タイトル: ${title}, 価格: ${price}`);
})

FireStoreから任意のコレクションを削除します

スクリーンショット 2021-12-26 23.34.08.png

削除処理をトリガーできれば成功

スクリーンショット 2021-12-26 23.48.13.png

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?