AWS API Gateway から Lambda を呼んで DynamoDB からデータを読み出してみた

AWS API GatewayからLambdaを呼んでDynamoDBからデータを読み出すメモ。

## 事前準備と前提条件

* AWS CLIを使えるようにしておく。
* リージョンは us-east-1 でやった。東京リージョンはまだAPI Gatewayが使えないという情報があったので(未確認)。

## DynamoDBにテーブルを作る

```
aws dynamodb create-table --attribute-definitions AttributeName=id,AttributeType=N AttributeName=timestamp,AttributeType=N --table-name reinvent2015_iot_ph_demo_dynamodb --key-schema AttributeName=id,KeyType=HASH AttributeName=timestamp,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=2
```

Hash key: `id` Range key: `timestamp` です。

## Lambdaにfunctionを作る

```
aws lambda create-function --function-name get_item --runtime nodejs --handler index.handler --role arn:aws:iam::941798529319:role/lambda_dynamo --zip-file fileb://Downloads/get_item-c93eb7e3-4bff-4e2b-a541-ebd93c608849.zip
```

`--role` の引数を良く理解してない。Webコンソールで作ったやつのHTMLソースから`<option>`タグのvalueをコピペしたら動いた。CLIだけでやるなら、予めRoleを作ってからそれを指定する、とかやるんだろうきっと。

`--zip-file` の引数にはLambdaのWebコンソールからダウンロードしたzipファイルを指定した。中身は `index.js` が入ってて、その中身は以下の通り。

```
console.log('Loading function');

var doc = require('dynamodb-doc');
var dynamo = new doc.DynamoDB();

exports.handler = function(event, context) {
    console.log('Received event:', JSON.stringify(event, null, 2));
    var params = {};
    params.TableName = "reinvent2015_iot_ph_demo_dynamodb";
    params.KeyConditions = [dynamo.Condition("id", "EQ", 1),
                            dynamo.Condition("timestamp", "GE", isNaN(parseFloat(event.timestamp)) ? (new Date().getTime() / 1000 - 180) : parseFloat(event.timestamp))];
    dynamo.query(params, function(err, data) {
        if (err) {
            context.fail(new Error('Unknown error occured'));
        } else {
            var response = {"items":data.Items};
            context.succeed(response);
        }
    });
};
```

Webコンソールでは直接コードをいじれるので、いざとなればコピペでイケる。

## API Gatewayを作る

AWS CLIが未対応なので、Webコンソールでやる手順を書く。(REST APIはあるので、がんばれば作れるらしいけど…)

1. https://console.aws.amazon.com/apigateway/home?region=us-east-1#/apis を開く。
2. `Create API` ボタンを押して適当な名前を付けて作る。
3. `Create Method` ボタンを押して `GET` メソッドを作る。
4. Integration Type = Lambda Function, Lambda Region = us-east-1, Lambda Function = `get_item`
5. Integration Request → Add mapping Template → Content-Type = `application/json`
6. 編集ボタン(右に出てきた鉛筆アイコン)を押して Template のテキストエリアに以下のコードを貼り付けて保存する。保存ボタン(チェックマークみたいなアイコン)を押すのを忘れずに。
```
{
  "id": "$input.params('id')",
  "timestamp": "$input.params('timestamp')"
}
```
7. `TEST` ボタン押して動いたらOK。`Deploy API`ボタンを押してデプロイして完了。おつした。

## API GatewayにCORSを設定する

1. OPTIONS Methodを作る。
    1. 作ったMethodを開く。
    2. Method Response → ▼ → Add Header → `Access-Control-Allow-Origin` `Access-Control-Allow-Methods` `Access-Control-Allow-Origin` を追加・保存する。
    3. Integration Response → ▼ → Header Mappings → Access-Control-Allow-Headers = `'Content-Type,X-Amz-Date,Authorization,X-Requested-With,X-Requested-By,X-Api-Key'` Access-Control-Allow-Methods = `'GET,POST'` Access-Control-Allow-Origin = `'*'` を追加・保存する。
2. GET MethodのResponseを設定する。
    1. Method Response → ▼ → Add Header → `Access-Control-Allow-Origin` `Access-Control-Allow-Methods` `Access-Control-Allow-Origin` を追加・保存する。
    2. Integration Response → ▼ → Header Mappings → Access-Control-Allow-Origin = `'*'` を追加・保存する。

## あとがき

Lambdaすげー。もうこういう時代なんだなあ…