📝

公式docに書かれていない、firebase v9の Cloud Functionsのロケーション指定方法

2021/12/05に公開

はじめに

2021年8月25日から、Firebase JavaScript SDK の version 9 が正式にリリースされました。
必要な関数のみをインポートすることで、ファイルサイズを従来より格段に小さくすることが出来るようになりました。
少しでも軽くしようと日々奮闘していらっしゃるエンジニアの方からすれば、神アプデだったのではないでしょうか?👏

しかし公式ドキュメントを読んでいるうちに、未だに version 8 の書き方で書いてあるところを見つけました。

それが、本記事の Cloud Functions のロケーション指定方法です。
該当ページ:Cloud Functions のロケーション

その結果、「公式の通りやっているのに、うまくいかない😢」という事態が起きてしまっています。

これから Functions を触る皆さんにこんな無為な時間を過ごさせてはさせてはならない……🔥という強い使命感を持って、この記事を書くことにしました。

※本記事では特に断りが無い限り、Cloud Functions とは Cloud Functions for Firebase のことを指します。(GCP が提供している Cloud Functions と区別しています。)

環境

Firebase 9.5.0

Cloud Functions のリージョンについての前提知識

Cloud Functions for Firebase とは

GCP の提供している Cloud Functions の公式ドキュメントでは、以下のように書かれています。

サーバー管理なしでコードを実行するためのスケーラブルな従量課金制 Functions as a Service(FaaS)

本記事で扱う Cloud Functions for Firebase はその中の一機能です。

Cloud Functions for Firebase では、同一プロジェクトの Cloud Firestore, Realtime Database, Cloud Storage の追加や編集、削除、またはこれらをトリガーとして functions を実行することができます。

例としては、

  • ユーザーが情報を変更した際( Firestore の値が変更された際)、ユーザーに確認メールを送る🚀
  • 外部APIを利用して、Cloud Storage に送られてきた画像から顔を検出し、アイコンとして切り出す👨

などが思い浮かびます。

このように、Cloud Functions では、Firebase の機能と他の API を組み合わせることが出来るため、Firebase 単体で使っているときと比べて自由度がぐんと高くなります。

Cloud Firestore, Realtime Database, Cloud Storage をある程度使えるようになってきて、もうちょっと自由度高い機能ないかな~と思った時に初めてお世話になる機能です。(多分)

Cloud Functions のロケーション

ロケーションは、サーバーが置かれている場所です。
サーバーにアクセスする際に、サーバーとの物理的な距離が近いほどレスポンスが早くなります。

Cloud Functions を使う際、ロケーションはデフォルトで us-central1(アイオワ) に設定されますが、一緒にCloud Firestore, Realtime Database, Cloud Storage を使用する場合は、以下のように Cloud Functions の推奨リージョンが変化します。

トリガーのタイプ リージョンの推奨事項
Cloud Firestore Cloud Firestore インスタンスの場所に最も近いリージョン(※例外あり[1])
Realtime Database 常に us-central1
Cloud Storage Cloud Storage バケットの場所に最も近いリージョン(※例外あり[1:1])
その他 関数内で Realtime Database、Firestore インスタンス、または Cloud Storage バケットとやり取りしている場合、それらのリソースのいずれかでトリガーされる関数があれば、推奨されるリージョンはそのリソースと同じリージョンです。それ以外の場合は、デフォルトのリージョン us-central1 を使用してください。Firebase Hosting に接続されている関数は us-central1 に配置する必要があります。

例えば、日本人向けのプロダクトを作るために Cloud Firestore のリージョンを asia-northeast1(東京) とし、Cloud Functions からいじろうとする場合は、Cloud Functions のリージョンも asia-northeast1(東京) に設定するのが良いということです。

Cloud Functions の使用方法

Cloud Functions をクライアントサイドから使う場合は、

  • functions 本体(HTTP関数、または 呼び出し可能関数)
  • そのfunctionを呼び出すためのクライアントサイドの関数

上記2つの関数が必要です。

上記のfunctions本体に記載した「HTTP関数」と「呼び出し可能関数」ですが、それぞれ「HTTP 通信を伴う関数の一般名称」、「クライアントサイドから呼び出せる関数の一般名称」という意味ではありません。

前者はfunctions.httpsを、後者はfunctions.https.onCall を使用して定義された関数のことを指します。Firebaseでは、この二つの関数を明確に区別しています。

今回は、HTTP 関数と、呼び出し可能関数それぞれについてロケーションを指定しようと思います。

HTTP 関数

HTTP 関数のデプロイ

関数の実行リージョンを設定するには、次に示すように、関数定義で region パラメータを設定します。

exports.myStorageFunction = functions
    .region('europe-west1')
    .https.onRequest((req, res) => {
     // ...
});

その後、firebase deploy --only functions コマンドによってデプロイします。

クライアントサイドからの呼び出し

デプロイした HTTP 関数をクライアントサイドから呼び出す方法については、単純に HTTP 通信を行う際の URL に、デプロイしたロケーションを書いてあげれば良いです。

これは、公式ドキュメントの「HTTP 関数の呼び出し」にも書かれています。

https://us-central1-<project-id>.cloudfunctions.net/date // us-central1の場合
https://asia-northeast1-<project-id>.cloudfunctions.net/date // asia-northeast1の場合

呼び出し可能関数

デプロイ

HTTP 関数と同じように、関数定義のタイミングで region パラメータを設定します。

exports.myCallableFunction = functions
    .region("asia-northeast1")
    .https.onCall((data, context) => {
    // ...
});

その後、firebase deploy --only functions コマンドによってデプロイします。

クライアントサイドからの呼び出し(本題)

ここまでは公式ドキュメントに書いてあることを長々と書いてきました。
ここからが、ようやく本記事の本題です。

呼び出し可能関数のリージョン変更について、2021年12月1日現在、公式ドキュメントでは以下のように書かれています。

呼び出し可能関数については、HTTP 関数と同じガイドラインに従って、クライアント側の呼び出し可能関数の設定を行う必要があります。クライアント側でもリージョンを指定できます。us-central1 以外のリージョンで関数を実行する場合は、リージョンを指定する必要があります。

クライアント側でリージョンを設定するには、初期化時に目的のリージョンを指定します。

var functions = firebase.app().functions('europe-west1');

なるほど、このまま書けばいいのか!
……と素直に書くと実行時エラーとなります。

実は、上記の記述は version 8 の書き方であって、version 9 には firebase.app()というメソッドは用意されていません。

どうすればいいのでしょう?

version 9 の書き方を公式ドキュメントに書いてないか探していると、API リファレンス:Functions interface を見つけました。

Functions のプロパティについて、以下のように書いてあります。

Property Type Description
app FirebaseApp The FirebaseApp this Functions instance is associated with.
customDomain string or null A custom domain hosting the callable Cloud Functions. ex: https://mydomain.com
region string The region the callable Cloud Functions are located in. Default is us-central-1.

要するに、functionsのプロパティにはregion というものがあり、これを変えれば良さそうです。

cliantside.js
import { getFunctions, httpsCallable } from "firebase/functions";

const functions = getFunctions();
functions.region = "asia-northeast1" // これを追加
const myCallableFunction = httpsCallable(functions, 'myCallableFunction');
myCallableFunction({ text: messageText })
  .then((result) => {
    const data = result.data;
    const sanitizedMessage = data.text;
  })
  .catch((error) => {
    const code = error.code;
    const message = error.message;
    const details = error.details;
    // ...
  });

これで、無事に呼び出し可能関数をクライアントサイドから呼び出すことが出来ました。

終わりに

Firebase の公式ドキュメントの更新が間に合っておらず、惑わされてしまいましたが、最終的に解決できたので良かったです。

あと、今気づいたのですが、ロケーションと言ったり、リージョンと言ったり言葉がブレッブレですね。。。🙃
ただ Firebase 公式も特に区別なく使っているようなので、このままにしようと思います。

Cloud Functions のロケーションを変更したい場合は参考にしてみてください。

宣伝

自分の所属している団体について1つ宣伝を...

GeekSalon という大学生限定のプログラミングコミュニティでは、完走率 80%以上、プロダクトは受講生の作りたいものを作り、学生メンターが受講生と併走しながら自分の力で 1 つアプリケーションを 3 ヶ月で完成させる経験を 約 10 万円近くの価格で提供しています。

自分が講師をしている WebExpert コースでは、JavaScript を学んで Vue を使った WEB アプリケーション開発をチームで行います。
もし大学生の方でチーム開発に興味があったら、説明を聞いてみてください。(定期的に説明会を開いてます。)

https://geek-salon.com/

参考文献

Firebase CloudFunctions 公式ドキュメント

脚注
  1. Cloud Functions で使用可能なリージョンは、Cloud Firestore データベースと Cloud Storage バケットで利用可能なリージョンと常に一致するわけではないので、いくつかの地域では Cloud Functions のリージョンを他の地域にする必要があります。) ↩︎ ↩︎

Discussion