Cloud Functions for Firebaseのver1.0が発表されたので、旧版からの変更点を確認する

# Cloud Functions for Firebaseのver1.0がリリースされました

今朝、メールを確認するとFirebaseチームから「[Important] API changes in new v1.0 of Cloud Functions for Firebase」が届いていました。中を読んでみると、**「Today, we’re pleased to release version 1.0 of the Cloud Functions for Firebase SDK!(（今日、Cloud Functions for Firebase SDKの1.0をリリースしたよ！）」**の文字が！

β版リリースから一年強のテスト期間を経て、ついに**Cloud Functions for Firebaseがver1.0リリース**となったようです。

とりあえず小躍りしながら変更点を確認してみたので、その内容をご紹介します。

> お詫びと訂正
> ver1.0なので正式版だと思ったのですが、ブログの最後に「まだベータ版」だと書いてありました。
> 「正式版」としていたところを「ver1.0」としました。お詫びして訂正します。

# TL;DR

- クライアントアプリケーションからFunctionsの関数を直接呼び出すことができるようになった
- Functionsのユニットテストが簡単になった
- コンソールの監視機能に「正常性」が追加された
-  [**重要**] APIの更新
    - 新しいSDKにアップデートするには、旧版で既に作成したコードをいくつか更新する必要がある

# 旧版からの変更点

## クライアントアプリケーションからFunctionsの関数を直接呼び出すことができるようになった

今回のアップデートでiOS、android、WEBアプリなどのクライアントサイドから、Functionsの関数を呼び出せるようになりました。

「Firebase SDK for iOS」「Firebase SDK for Android」「Firebase JavaScript SDK」といったSDKをクライアントサイドに導入することで、functionsにExpressのようなライブラリを入れずに直接通信を行うことができるようになります。

なお、このSDKを使ってリクエストする場合、ユーザーがログインしている状態ならリクエストにFirebase認証のユーザーIDトークンやFirebase Cloud Messagingで使用されるインスタンスIDトークンも含まれるようになります。

**funcsionsの記述例**

```javascript
// functions.httpsが追加されました
exports.addNumbers = functions.https.onCall((data) => {
  // [START readAddData]
  // data引数から、クライアント側のデータを取得
  const firstNumber = data.firstNumber;
  const secondNumber = data.secondNumber;
  // [END readAddData]

  // [START addHttpsError]
  // 要素の存在チェックと型チェック
  if (!Number.isFinite(firstNumber) || !Number.isFinite(secondNumber)) {
    // エラーの詳細をクライアントに送信
    throw new functions.https.HttpsError('invalid-argument', 'The function must be called with ' +
        'two arguments "firstNumber" and "secondNumber" which must both be numbers.');
  }
  // [END addHttpsError]

  // [START returnAddData]
  // 結果をクライアントに返す
  return {
    firstNumber: firstNumber,
    secondNumber: secondNumber,
    operator: '+',
    operationResult: firstNumber + secondNumber,
  };
  // [END returnAddData]
});
```

## Functionsのユニットテストが簡単になった

今度のアップデートで`firebase-functions-test`というnpmモジュールが追加され、ユニットテストがしやすいようになりました。

これまでfunctionsではテスト用のデータと実データが分かれていなかったため、（そのまま使うと）本番データに与える影響に不安がありましたが、このモジュールを使うえば完全にオフラインで、かつ実データに影響を与えることなく、データベースとの対話テスト等も行うことができます。

**funcsionsの記述例**

```javascript
// [START fakeEvent]
// Realtime Detabaseのテスト用イベントを使用する例
const fakeEvent = {
// DeltaSnapshotコンストラクタは、Functions SDKによって、データベース本来イベントを.val()などのユーティリティ関数をもったオブジェクトに変換するために使用されます。
// クラス型： DeltaSnapshot(app: firebase.app.App, adminApp: firebase.app.App, data: any, delta: any, path?: string);
data: new functions.database.DeltaSnapshot(null, null, null, 'input'),
};
// [END fakeEvent]
```

また、これまでテスト段階とされてきた `firebase serve - only functions`と`firebase experimental：functions：shell`コマンドが公式サポートされることになりました。
"firebase experimental：functions：shell"は "firebase functions：shell"に名前が変更となっているので注意してください。

## コンソールの監視機能に「正常性」が追加された

FirebaseコンソールのFunctionsページに、新しいタブ「正常性（英語名ではHEALTH）」が追加されました。「正常性」ではデプロイした関数のエラー状況を監視することができます。
（今までダッシュボードで小さく表示されていたグラフがこちらに移ったようです。）

![エラー状況](https://4.bp.blogspot.com/-F7Lb5Mc6RMA/WsQGUNOD-XI/AAAAAAAAB-k/R9E_CIVXODQEjnrKiOLNa4JCzK3gYQBawCLcBGAs/s1600/functions-health-tab-errors.png)

また、「正常性」の下方にはその関数のパフォーマンス、レイテンシ、メモリ利用状況も確認できるようになっており、エラーとなっていない異常値の検知をすることができるようになりました。

![パフォーマンス](https://3.bp.blogspot.com/-ByKCO2qxujQ/WsPF3fj2j5I/AAAAAAAAB98/xo61gmti1VYC_-_pTZRrxtJMWfA0uom3wCLcBGAs/s1600/image4.png)

## [重要] APIの更新

このv1.0 SDKリリースで、Firebase SDKでCloud Functionsを記述するためのAPIが変更されました。
つまり、**新しいSDKにアップデートするには、旧版で既に作成したコードをいくつか更新する必要があります。**

ただ、これは既にデプロイしている機能には影響しません。
変更された内容と新しいフォーマットに適応する方法を確認するには、それぞれのAPI記述を変更する必要がありますが、Firebase側で移行ガイドを用意しているようですので、アップデート時にはその[移行ガイド](https://firebase.google.com/docs/functions/beta-v1-diff)を参照してください。

**SDKの更新方法**

```bash
npm install firebase-functions@latest --save
npm install firebase-admin@5.11.0 --save
```

**API更新の例 1 (config)**

```javascript

// Before (<= v0.9.1)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

// Now (v1.0.0)
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
```

**API更新の例 2 (Cloud Firestore)**

```javascript

// Before (<= v0.9.1)
exports.dbWrite = functions.firestore.document('/path').onWrite((event) => {
  const beforeData = event.data.previous.data(); // data before the write
  const afterData = event.data.data(); // data after the write
});

// Now (v1.0.0)
exports.dbWrite = functions.firestore.document('/path').onWrite((change, context) => {
  const beforeData = change.before.data(); // data before the write
  const afterData = change.after.data(); // data after the write
});
```

## 参考ソース

[公式ブログ](https://firebase.googleblog.com/2018/04/launching-cloud-functions-for-firebase-1-0.html)
[公式ドキュメント](https://firebase.google.com/docs/functions/)