2020-12-28

CloudFunctions for Firebaseの環境変数管理

技術

CloudFunctions for Firebaseの環境変数はよくあるパターンとは異なり、

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

で実環境の環境変数を設定し、JSプログラムから取得する場合は

const functions = require('firebase-functions');

const SOME_SERVICE_ID = functions.config().someservice.id

のように取得する。

普通のパターンなら dotenv 等を使用して管理する所だが、違うパターンのため環境変数は以下のように管理するようにした。

使用するパッケージ

  • config
  • lodash/get

本番/ステージング環境では前述のように functions.config() 経由で環境変数を取得し、それ以外のエミュレータやテスト環境では、 config パッケージを使用して管理・取得するようにした。

例えば、 config/test.json

{
  "someservice": {
    "key":"THE API KEY",
    "id":"THE CLIENT ID"
  }
}

のような設定ファイルを用意し、Node.jsプログラムでは以下のように取得している。

import * as functions from 'firebase-functions'
import config from 'config'
import get from 'lodash/get'

export const NODE_ENV = (() => {
  const value = process.env.NODE_ENV ?? 'production'

  if (value === 'production' || value === 'emulator' || value === 'test') {
    return value
  }

  throw new Error('NODE_ENV must be production or emulator or test')
})()

const getConfig = () =>
  NODE_ENV === 'production' ? functions.config() : config

const getEnvValue = (path: string) => {
  const value = get(getConfig(), path)
  if (value === undefined) {
    throw new Error(`env ${path} is undefined`)
  }

  return value
}

export const SOME_SERVICE_KEY = getEnvValue('some_service.key')

export const SOME_SERVICE_ID = getEnvValue('some_service.id')

工夫したところは lodash/get 関数を使用してオブジェクトにアクセスしている箇所。環境変数は設定し忘れをすることが多く、その際にはできるだけ早く例外を吐いて落ちて欲しい。そのためには環境変数取得処理を共通化しないとコードが乱雑になってしまうが、 lodash/get 関数を使うことで共通化出来た。get(someObject, 'foo.bar.baz') みたいに文字列で取得するキーを指定できる関数が欲しかった所 lodash/get がまさにそれだった。

あとは config パッケージは NODE_ENV によって読み込む設定ファイルを変更するため、例えばテストの際は NODE_ENV=test jest のようにすればOK。