【便利】Cloud Firestoreのrulesで値を確認できるdebug()関数

[firebase-tools](https://github.com/firebase/firebase-tools)のv6.4.0から、Cloud Firestoreのrulesで使える`debug`関数が追加されました。

> Introduced debug(...) function to Firestore emulator security rules

はじめはどう使うのか分からず「そういうのがあるんだなー」くらいで流していたのですが、先日使い方を知ることができたのでさくっとまとめてみます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">firebase-toolsのv6.4.0に入っていた、firestoreのrulesで使えるdebug(...)、便利なのでは<a href="https://t.co/JPEvsgEAUr">https://t.co/JPEvsgEAUr</a></p>&mdash; su- (@_sgr_ksmt) <a href="https://twitter.com/_sgr_ksmt/status/1116679008152772609?ref_src=twsrc%5Etfw">April 12, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## どういうものか
`debug()`関数は、`firestore.rules`内に記述できる関数で、この関数の引数に渡した情報を、出力してくれます。
名前の通り、debug目的で使うものとなっていて、Firestore Emulatorを起動している状態でのrulesのテスト等に活用することができます。
Emulatorを起動した状態で、該当のルールが評価されるタイミングで、debug(...)内の値がEmulatorを実行しているターミナルに出力されます。

## 使い方

```js
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow write: if debug(request.auth.uid) != null;
    }
  }
}
```

例えばこのように`request.auth.uid`をdebug関数で包み、

```js
const db = firebase
  .initializeTestApp({
    projectId: project_id,
    auth: { uid: 'alice'}
  })
  .firestore()
```

として初期化したfirestoreを使ってテストを書くと、次のようにターミナル上に出力されます

```bash
string_value: "alice"
```

## 出力できる形式
出力できるものとしては、 [リファレンスに記述のある型](https://firebase.google.com/docs/reference/rules/rules)となります。
あとはnullも出力されます。

```bash
null_value: NULL_VALUE
```

`resource` を試しに出力してみるとこのようになります

```js
map_value {
  fields {
    key: "data"
    value {
      map_value {
        fields {
          key: "birthday"
          value {
            string_value: "January 1"
          }
        }
      }
    }
  }
  fields {
    key: "__name__"
    value {
      path_value {
        segments {
          simple: "databases"
        }
        segments {
          simple: "(default)"
        }
        segments {
          simple: "documents"
        }
        segments {
          simple: "users"
        }
        segments {
          simple: "alice"
        }
      }
    }
  }
  fields {
    key: "id"
    value {
      string_value: "alice"
    }
  }
}
```

### 出力されないもの
debug関数に渡したものが、`undefined` や評価結果としてerrorになってしまっているものに関しては出力されません。
その場合はEmulator側でログが吐き出されていたり、テストでerrorをcatchして情報を得ることができます。

```bash
FirebaseError: [code=permission-denied]:
Property xxx is undefined on object. for 'get' @ L12
    at FirestoreError.Error (native)
```


## ちょっと便利になるやつ
次のような関数を準備してあげると、requestやresourceの状態を出力しつつ、後続の条件をそのまま評価できるようになるので便利です。

```js
service cloud.firestore {
  function printRequest() {
    return debug(request) || true;
  }

  function printResource() {
    return debug(resource) || true;
  }

  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if printResource() && request.auth.uid != null;
      allow write: if printRequest() && request.auth.uid != null;
    }
  }
}
```

## 【注意】deploy前にはdebug関数を消そう
debug関数を書いたままdeploy自体はできますが、実際に実行されるときにはdebug関数自体は未定義になり、errorが発生するので注意です。
試しにdebug関数を書いたままdeployし、webコンソールのルールシミュレーターで該当する部分の検証を行うと次のようなエラーが出ると思います。

<img width="768" alt="スクリーンショット 2019-04-14 14.31.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27802/5c99f0ea-f9b5-d2d6-9c86-28eef415e3e0.png">



## まとめ
今まではある変数に格納されている値がなんであるのか、関数を評価した結果何が帰っているか分かりづらかったのですが、debug関数の登場により原因を特定しやすくなるかと思います。
「ruleは書いたもののうまく動かない」、「ここの値これが入ってくるはずなのにうまく動いていない」というときに活用してみてください。

## 参考
- [Documentation: debug() function for Firestore emulator](https://github.com/firebase/firebase-tools/issues/1166)