Firebase Functions https.onCall()トリガーでアプリから簡単に呼び出す

Firebase Fuctionsとは

Firebase Functionsとは、Firebaseの提供するサーバレスフレームワークです。HTTPSリクエストによって関数を実行したり、FireStore・Cloud Storage・AuthenticationのCRUDイベントをトリガーに関数を実行することができます。(残念ながら、無料プランでは利用することはできません・・・)AWS Lambdaに近い機能だと言えます。使用できる言語はJavaScript・TypeScriptに限られているというデメリットはあるものの、手軽にデプロイでき簡単にプロジェクトの他のFirebaseの機能と統合できるメリットがあります。

環境構築

firebase CLIのインストール

Node.jsがインストールされていることが前提です。 まずは、firebase CLIをインストールします。

npm install -g firebase-tools

インストールが完了したらバージョンを確認します。

firebase --version
9.1.0

プロジェクトの初期化

まずははじめに、下記コマンドでfirebaseツールを認証する必要があります。

firebase login

ブラウザに遷移するのでログインします。

次に、プロジェクトを作成します。コマンドを実行したディレクトリに作成されるので、予めディレクトリをほっておきましょう。

firebase init functions

通常のHTTPリクエスト

HTTPリクエストを処理する場合には、firebase.httpsを使用します。この関数は、Expressと統合することも可能です。

import { https } from 'firebase-functions'

export const hello = https.onRequest((req, res) => {
  res.status(200).json('Hello!')
})

npm run serveコマンドで、ローカル環境で実行することができます。 エンドポイントはhttp://localhost:5001/<project-id>/us-central1/<exoprtした関数名>(hello)です。

アプリから呼び出すときは、通常のREST API同様axiosなどを用いてリクエストを送ることになるでしょう。この例では省略をしていますが実際にはサーバー側でCORSの設定をする必要があるでしょう。

const { data } = axios.get('http://localhost:5001/<project-id>/us-central1/hello`

onCallを利用する

これだけでもサーバレスとしての機能として申し分ないですが、https.onCall関数を利用することでさらに簡単に処理を行うことができます。

onCall関数は次のようになります。

import { https } from 'firebase-functions'

export const hello = https.onCall((data, context) => {
  return 'Hello!'
})

onCall関数は、2つの引数を受け取ります。dataには送信されたパラメータが、contextにはFirebase Authenticationによる認証情報が含まれています。

import { https } from 'firebase-functions'

export const hello = https.onCall((data, context) => {
  const { id, name } = data
  const { auth, instanceIdToken, rawRequest} = context

  auth?.token
  auth?.uid
})

簡単に認証情報が利用できるのがonCall関数の特徴です。通常認証情報を付与してHTTPリクエストを送信するには、Authentication Headerに bearer tokenといった形で付与して検証するのが一般的ですが、このようなめんどくさい決まりきった処理をすべて行ってくれます。

レスポンスを返すには、JSONエンコード可能なデータをreturnすればOKです。

import { https } from 'firebase-functions'

export const user = https.onCall(async (data, context) => {
  const user = await User.find(context.auth.uid)

  return {
    firstName: user.firstName,
    lastName: user.lastName,
    age: user.age
   }
})

エラーを処理するには、https.HttpsErrorをスローします。https.HttpsErrorの第一引数にエラーコードを、第二引数にエラーメッセージを渡します。 第一引数に渡せるエラーコードは以下の通りです。

FunctionsErrorCode: "ok" | "cancelled" | "unknown" | "invalid-argument" | "deadline-exceeded" | "not-found" | "already-exists" | "permission-denied" | "resource-exhausted" | "failed-precondition" | "aborted" | "out-of-range" | "unimplemented" | "internal" | "unavailable" | "data-loss" | "unauthenticated"

https://firebase.google.com/docs/reference/functions/providers_https_?hl=ja#functionserrorcode

import { https } from 'firebase-functions'

export const user = https.onCall(async (data, context) => {
  if (!context.auth) {
    throw new https.HttpsError('unauthenticated', 'auth error')
  }
  const user = await User.find(context.auth.uid)

  return {
    firstName: user.firstName,
    lastName: user.lastName,
    age: user.age
   }
})

アプリから呼び出す

onCallで作成した関数をアプリから呼び出してみましょう。

import firebase from 'firebase'
import 'firebase/functions'

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
  databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
})

const functions = firebase.functions()

if (process.env.NODE_ENV === 'development') {
  functions.useEmulator('localhost', 5001)
}
const func = functions.httpsCallable('user')

const result = func({ id: 'id', name: 'name' })

firebase.functions().httpCallable()で、onCall()で作成した関数を呼び出すことができます。デフォルトの呼び出しですと、デプロイされたFirebase FunctionsのURLを見に行きますので、ローカル環境でFirebase Functionsを利用している際にはfirebase.functions().useEmulator()でリクエストを送るURLを指定します。

firebase.functions().httpsCallable()の返り値の関数を呼び出すことで、実際にリクエストが送られます。 この引数に渡した値は、onCallの第一引数のdataから受け取ることができます。

見ての通り、認証情報に関する処理は全くありません。Firebase Authenticationでログインしていれば自動的にAuthentication Headerにトークンを付与してくれます。

この記事をシェアする
Twitterで共有
Hatena

関連記事