AWS Lambda@Edge で 環境変数を使う方法 (Node.js)

### はじめに

Lambda ならば、環境変数という項目があり、
そこにキーと値を書けば `process.env` オブジェクトから取得できました。

参考URL

[AWS Lambda で環境変数を渡してみる(Node.js)](https://qiita.com/hkusu/items/e10a6b1b07ebffcd1b08)

Lambda@Edge にも同じく環境変数の入力欄があるのですが、
どういうわけかまだサポートされてないらしく、
2020年2月時点では使用できません。

初見殺しもいいところですね。

でも、環境変数が使いたい時はあると思います。
色々模索した結果、以下の方法に落ち着きました。

### 結論 `dotenv` ライブラリを使う

ローカル環境とかにdotenvライブラリを導入します

```bash
$ cd /path/to/project
$ npm install dotenv
```

次に、 `.env` ファイルを用意して、そこに環境変数を色々書いておきます。

```bash
$ touch .env
$ vi .env
```

私はかつてLaravel5(PHP)を使っていたので、それに習った書き方をしています。
Laravelいいよね。

```:.env
APP_ENV=production
APP_URL=https://www.example.com
APP_DEBUG=false
```

ここまで出来たら、これらをZIPファイルにまとめて、
Lambda@Edgeにアップロードします。

ZIPファイルでアップロードする方法は、
ネットに腐るほど書いてますのでググってください

### 【絶対にすること】 エディタで隠しファイルを表示する

2020.02.19 追記

下の方法よりもっと簡単な方法がありました。
プロジェクトフォルダの右の歯車をクリックした後、「Show Hidden Files」をクリックするだけです

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/d20c6a3b-6c43-02f2-0af1-cd830949c03f.png)


ファイルアップロードが終わったら、
以下の手順に従い、コンソールエディタで
「.env」などの隠しファイルが表示されるようにしてください
(将来の Lambda@Edge のアップデートで表示方法が変更になる可能性があります)

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/58c06522-7916-27ea-1f6c-56ffcb6d855d.png)

① エディタ右上の歯車マークをクリック
② User Settings をクリック
③ Tree and Go Panel をクリック
④ Hidden File Pattern: から 次のように 「, .*」 を削除

```
*.pyc, __pycache__, .*
↓
*.pyc, __pycache__
```

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/eb2146fa-2350-c43f-3b7a-b38bb791b47e.png)


これにより、隠しファイルが表示されるので
どこに設定ファイルがあるかがわかるようになりますね。

(筆者は動作確認のために .envファイルを複数用意していますが、
必要ありません。「.env」ファイルだけが使用されます)

### 環境変数の取得方法

Lambdaで環境変数を取得する方法と全く同じやり方で取得できます。
つまり、 `process.env` オブジェクトから取得できます。

```javascript
var ENV = require('dotenv').config();
var appUrl = process.env['APP_URL'];
console.log(appUrl); // e.g. "https://www.example.com"
```

私の場合、毎回 `process.env` って書くのがだるいので
Laravelのenv関数みたいな感じにラッピングしてから使用しています

```javascript:index.js
/* =====================================================================
*  Load External Modules
* =================================================================== */
try {
  var ENV = require('dotenv').config(); // 環境変数が使えるようになったらこのモジュールは不要
}
catch(ex){ // if module is not exists
  console.error(ex);
}

/**
 * Get Envrionment Variable
 * Lambda@Edgeは2020年2月時点では環境変数が使えないから
 * DotEnvライブラリで代用する(環境変数もDotEnvも process.env で値を取得できる)
 *
 * @param  string key (should be write UPPERCASE)
 * @param  mixed defaultValue [optional]
 * @return mixed
 */
function getEnv(key, defaultValue = null)
{
  var myKey = key.toUpperCase();
  return process.env[myKey] ? process.env[myKey] : defaultValue;
}

function loadProfile()
{
  var env = new Object();
  env.APP_URL = getEnv("APP_URL", "https://www.example.com");
  env.APP_ENV = getEnv("APP_ENV", "development");
  env.APP_DEBUG = getEnv("APP_DEBUG", true);
  env.S3_BUCKET_NAME = getEnv("S3_BUCKET_NAME", "my-s3-bucket-name");
  env.EC2_URL = getEnv("EC2_URL", "");
  return env;
}

exports.handler = async (event, context, callback) => {
  var request = event.Records[0].cf.request;

  var env = loadProfile();

  console.log(env["APP_URL"]); // e.g. "https://www.example.com" 
  console.log(env["APP_ENV"]); // e.g. "production" .env に定義されているので その値が使用される
  console.log(env["S3_BUCKET_NAME"]); // e.g. "my-s3-bucket-name" .env に定義されていないので getEnv関数の第2引数が使用される

  callback(null, request);
};
```

もっと良い方法をご存知の方が
いらっしゃいましたらコメントください。