【AWS】API GatewayのステージとLambda のエイリアスを対応させる

# 背景
LambdaとAPI Gatewayをセットで使う場合、**両サービスはそれぞれに状態を持っている**(LambdaはVersionとAlias、API GatewayはDeployment Stage)為、それらの**関連性を管理する必要があり**ます。

具体的には、API Gatewayのdevステージでは、Lambda functionのdevエイリアスを使うなど、自分たちである程度ルールを作り運用することができれば、**開発が捗りそう**です :kissing: 

そんな時は、**API Gatewayの`${stageVariables}`を使って、両者の関係を紐付ける**ことができます。

# やってみる

## Lambda

まずはサンプルのLambdaを作ります。このLambdaはバージョン管理し、それぞれに`dev`と`prod`というエイリアスを付けてあります。

バージョン管理されたLambdaでは、`$LATEST`のlambda functionしか修正できません。そのため、古いバージョンを`prod`に、$LATESTを`dev`にしてあります。

functionの中身は、以下のようにシンプルなものです。

* `dev`エイリアス  : {`Message`: `Hello World!`} を出力する
* `prod`エイリアス : contextオブジェクトを出力する

devエイリアス
<img width="753" alt="Screen Shot 2016-02-03 at 12.00.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/01425222-0110-1f8b-c1cf-0054d5153957.png">

prodエイリアス
<img width="717" alt="Screen Shot 2016-02-03 at 12.01.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/d820b876-64ab-104e-823b-418f1a3a39e7.png">

これで、同名のLambdaを別エイリアスで呼び出す準備ができました。

## API Gateway
次に、API Gatewayを作ります。

### Resource
ResourceにGETを追加し、`Integration type`にLambda Functionを選択します。**`Lambda Function`の名前にstageVariablesを使うのが今回のポイント**です。

具体的には、`<Lambda Function>:${stageVariables.alias}`を設定しています。
<img width="894" alt="Screen Shot 2016-02-03 at 12.03.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/3d07d9e9-c1cc-1119-8497-fc3dfb4c1495.png">

### 権限設定

前述のResource作成時に、`Lambda　Function`名を決定すると、以下のようなモダルが表示されたと思います。これは、**API Gatewayがlambdaを実行する為の許可設定をawscli経由で行う**ことを教えてくれています。

<img width="896" alt="Screen Shot 2016-02-03 at 12.05.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/5c7c7d75-101c-af6a-09a4-8740956c2fd0.png">(一部マスクしてあります)

このコマンドはそのまま実行すれば良いのではなく、自分で`${stageVariables.alias}`を置き換えて実行する必要があります。（そのまま実行するとbad substitutionのエラーが返ってきます）

今回は、エイリアスにdevとprodを用意したので、`--function-name`オプションに `arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev`もしくは、 `arn:aws:lambda:ap-northeast-1:*****:function:myLambda:prod`に変えて実行した感じです。

```bash
$ aws lambda add-permission --function-name arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev --source-arn arn:aws:execute-api:ap-northeast-1:*****:hykf0+++++/*/GET/ --principal apigateway.amazonaws.com --statement-id 481173e7-a50b-4f48-a527-2137ddf13fe4 --action lambda:InvokeFunction
{
    "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:*****:hykf0+++++/*/GET/\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:*****:function:myLambda:dev\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"481173e7-a50b-4f48-a527-2137ddf13fe4\"}"
}

$ aws lambda add-permission --function-name arn:aws:lambda:ap-northeast-1:******:function:myLambda:prod --source-arn arn:aws:execute-api:ap-northeast-1:******:hykf+++++/*/GET/ --principal apigateway.amazonaws.com --statement-id 481173e7-a50b-4f48-a527-2137ddf13fe4 --action lambda:InvokeFunction
{
    "Statement": "{\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:******:hykf+++++/*/GET/\"}},\"Action\":[\"lambda:InvokeFunction\"],\"Resource\":\"arn:aws:lambda:ap-northeast-1:******:function:myLambda:prod\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Sid\":\"481173e7-a50b-4f48-a527-2137ddf13fe4\"}"
}
```
これで、lambdaを呼び出す権限設定ができました。

## stageVariables
最後に、stageVariablesを設定します。API Gatewayの各Stageで設定できます。
Resourcesの"Deploy API"ボタンから、devとprodのステージを作成します。

dev、prodそれぞれのステージで、"Stage Variables"カラム を開き、stageVariablesを設定します。**Nameがaliasで、Valueは各環境**に合わせます。

<img width="674" alt="Screen Shot 2016-02-03 at 12.03.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/67720e44-1c89-dc97-dcea-7d9a316ceb44.png">

これで一通り完成です。

# 確認する
ResourcesのMethod Test画面を開くと、Stage Variablesを入力する欄が出てきます。そこに、devやprodなど入れてテストしてみましょう。

ちゃんとlambdaのエイリアスに紐付いて実行されています。

dev
<img width="1003" alt="Screen Shot 2016-02-03 at 15.48.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/4d13dd37-0c15-441f-5976-313a406d3bd8.png">

prod
<img width="1107" alt="Screen Shot 2016-02-03 at 15.49.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/18114/7b68f8b3-c597-f585-49f3-077d139f47fe.png">

各ステージごとのAPIを叩いても、同様の結果が返ってきました。
大丈夫そうですね :smile: 

```bash
$ curl -s https://hykf0*****.execute-api.ap-northeast-1.amazonaws.com/dev/ | jq
{
  "Message": "Hello World!"
}

$ curl -s https://hykf*****.execute-api.ap-northeast-1.amazonaws.com/prod/ | jq
{
  "awsRequestId": "f9ecaed0-ca15-11e5-86c6-41208cf01644",
  "invokeid": "f9ecaed0-ca15-11e5-86c6-41208cf01644",
  "logGroupName": "/aws/lambda/myLambda",
  "logStreamName": "2016/02/03/[4]092d13ef1c93490b832d36f3a6fa3eec",
  "functionName": "myLambda",
  "memoryLimitInMB": "128",
  "functionVersion": "4",
  "invokedFunctionArn": "arn:aws:lambda:ap-northeast-1:*****:function:myLambda:prod"
}
```

# まとめ
API GatewayのstageVariablesを使って、LambdaのAliasと連携させる話でした。

stageVariablesを使うと、ステージごとにURIを変更したり様々な要件に対応できそうです。積極的に使っていきたいところですね。


[参考]
https://aws.amazon.com/jp/about-aws/whats-new/2015/11/amazon-api-gateway-supports-stage-variables/
http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/amazon-api-gateway-using-stage-variables.html
https://aws.amazon.com/jp/blogs/compute/using-api-gateway-stage-variables-to-manage-lambda-functions/