Cloud Functions v2のロケーション設定(Firebase)

### 背景
- ロケーションの設定をせずにcloudFunctionsのデプロイを行うと、自動で`us-central1`にデプロイされてしまう
- ロケーションの設定をする際に第1世代と第2世代で記述方法が異なる

### 本記事の目的
- 世代の違いによるロケーション設定の記述方法を学ぶ
- ロケーションの設定をした場合に`us-central`を任意のリージョンに変更する


## Cloud Functions v1での記法

- onCall関数とschedule関数の実装方法
    - (※ 処理内容は適宜変更してください)

```index.ts
import { CallableRequest } from "firebase-functions/v2/https";

import { updateAllItems } from "./helper/updateAllItem";
import { registerItem } from "./helper/registerNewItem";
import { region } from "firebase-functions";

// 新規商品登録
// asia-northeast1は東京
exports.registerNewItem = region("asia-northeast1").https.onCall(
  async (request: CallableRequest) => {
    return await registerItem(request);
  }
);

// 商品情報の更新
// asia-northeast1は東京
exports.runScheduledJobs = region("asia-northeast1")
  .pubsub.schedule("every day 00:00")
  .timeZone("Asia/Tokyo")
  .onRun(async () => {
    await updateAllItems();
  });

```

- onCall関数
    - `firebase-functions`の`region.https.onCall`を使用
- schedule関数
    - `firebase-functions`の`region.pubsub.schedule`を使用


## Cloud Functions v2での記法

- onCall関数とonSchedule関数の実装方法
    - (※ 処理内容は適宜変更してください)

```index.ts
import { CallableRequest, onCall } from "firebase-functions/v2/https";
import { onSchedule } from "firebase-functions/v2/scheduler";

import "module-alias/register";

import { updateAllItems } from "@/helper/updateAllItem";
import { registerItem } from "@/helper/registerNewItem";

// 新規商品登録
exports.registerNewItem = onCall(
  { region: "asia-northeast1" },
  async (request: CallableRequest) => {
    return await registerItem(request);
  }
);

// 商品情報の更新
exports.runScheduledJobs = onSchedule(
  {
    region: "asia-northeast1",
    timeZone: "Asia/Tokyo",
    schedule: "every day 00:00",
  },
  async () => {
    await updateAllItems();
  }
);

```

- onCall関数
    - `firebase-functions/v2/https`から`onCall`をインポート

- onSchedule関数
    - `firebase-functions/v2/scheduler`から`onSchedule`をインポート

- 第2世代ではonCall, onSchedule内でロケーションやタイムゾーンなどの設定をすることが出来ます
    -  [リージョン名と場所の一覧](https://firebase.google.com/docs/firestore/locations?hl=ja)
    -  [定期実行の時刻の記述方法](https://cloud.google.com/appengine/docs/legacy/standard/python/config/cronref?hl=ja)

## 注意
- **クライアントサイドでも同一のリージョンに設定をしないとエラーになります**
    - クライアントサイドでのFirebaseのセットアップ(init.ts)
    ```init.ts
    import { initializeApp } from "firebase/app";
    import { getFunctions } from "firebase/functions";
    import { API_KEY, AUTH_DOMAIN, PROJECT_ID } from "@/env";

    const firebaseConfig = {
      apiKey: API_KEY,
      authDomain: AUTH_DOMAIN,
      projectId: PROJECT_ID,
    };
    const app = initializeApp(firebaseConfig);

    //第2引数にCloud Functionsと同一のリージョンを設定してください。
    export const functions = getFunctions(app, "asia-northeast1");
    ```


## あとがき
- Cloud Functionsには第1世代と第2世代の2つがあり、これらを共存して記述することが出来ないため、どちらかに統一する必要があります。今回は新しい第2世代で書きたいと思い、記述方法をまとめてみました。
第1世代ではメソッドを繋いで設定を書いていたのに対して、第2世代では引数に設定することが出来るため、簡潔に記述することが出来ます
- onCallやonSchedule関数を使いながらregionの設定をしている文献が公式ドキュメントを含めて無かったため、この記事が参考になると思います
- 世代の違いによって使用する関数や記述方法の違いにだいぶ戸惑ったので、この記事でこれらが解消されると幸いです

<br>

- 感想
リクエストが通らない原因がCloud Functions側のエラーだと思っていましたが、実際にはクライアントサイドによるエラーでした。気づくまでにだいぶ時間がかかりました。まだまだFirebaseの学習が必要ですね、、