Serverless Frameworkを使ったAPI Gateway + Lambda + DynamoDBのセットアップ方法まとめ

## 概要
[Serverless Framework](https://github.com/serverless)を使って、API Gateway + Lambda + DynamoDBのアプリケーションセットアップ方法をまとめる

## 初期セットアップ
### インストールからプロジェクトの作成まで
npmでServerlessをインストール

    $ npm install serverless -g

新規プロジェクトの作成

    $ serverless project create

<img width="530" alt="スクリーンショット 2016-03-15 18.16.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/65478/90762f51-4e76-5377-eb71-ddee83579467.png">
↑
こういうファイル構成ができている

### コンポーネントとファンクションの作成
    $ serverless component create component1
    $ serverless function create component1/function1

visibleというコンポーネントを作り、searchwordというファンクションを作る

```shell-session
[horike@horiketakahiro-no-MacBook-Pro elasticommerce-search-service]$serverless component create visible
Serverless: Installing "serverless-helpers" for this component via NPM...  
Serverless: -----------------  
serverless-helpers-js@0.1.0 node_modules/serverless-helpers-js
└── dotenv@1.2.0
Serverless: -----------------  
Serverless: Successfully created new serverless component: visible  
[horike@horiketakahiro-no-MacBook-Pro elasticommerce-search-service]$serverless function create visible/searchword
Serverless: Successfully created function: "visible/searchword" 
[horike@horiketakahiro-no-MacBook-Pro elasticommerce-search-service]$tree
.
├── README.md
├── _meta
│   ├── resources
│   │   └── s-resources-cf-dev-apnortheast1.json
│   └── variables
│       ├── s-variables-common.json
│       ├── s-variables-dev-apnortheast1.json
│       └── s-variables-dev.json
├── admin.env
├── package.json
├── s-project.json
├── s-resources-cf.json
└── visible
    ├── lib
    │   └── index.js
    ├── node_modules
    │   └── serverless-helpers-js
    │       ├── README.md
    │       ├── env
    │       │   └── index.js
    │       ├── index.js
    │       ├── node_modules
    │       │   └── dotenv
    │       │       ├── Contributing.md
    │       │       ├── README.md
    │       │       ├── config.js
    │       │       ├── dotenv.png
    │       │       ├── lib
    │       │       │   └── main.js
    │       │       ├── package.json
    │       │       └── test
    │       │           ├── config.js
    │       │           └── main.js
    │       └── package.json
    ├── package.json
    ├── s-component.json
    └── searchword
        ├── event.json
        ├── handler.js
        └── s-function.json

14 directories, 30 files
```

## API Gateway
### API Gatewayのリクエストの受け渡し周りの設定
`/path/to/project_root/`に`s-templates.json`を設置。プロジェクト全体で受け取るリクエストの値を決めます。

```json:/path/to/project_root/s-templates.json
{
  "apiRequestTemplate": {
    "application/json": {
      "httpMethod": "$context.httpMethod",
      "body": "$input.json('$')",
      "queryParams" : "$input.params().querystring",
      "headerParams" : "$input.params().header",
      "headerParamNames" : "$input.params().header.keySet()",
      "contentTypeValue" : "$input.params().header.get('Content-Type')"
    }
  }
```

`/path/to/project_root/visible/searchword`に`s-templates.json`を設置

```json:/path/to/project_root/visible/searchword/s-templates.json
{
  "apiRequestTemplate": {
    "application/json": {
      "searchword": "$input.params('searchword')"
    }
  }
}
```
`/path/to/project_root/visible/searchword`の`s-function.json`を修正
`endpoints`の`path`と`requestTemplates`を修正する

```json:s-function.json
"endpoints": [
    {
      "path": "searchword/{searchword}",
      "method": "GET",
      "type": "AWS",
      "authorizationType": "none",
      "apiKeyRequired": false,
      "requestParameters": {},
      "requestTemplates": "$${apiRequestTemplate}",
```

## Lambda
初期設定状態では複数のファンクションが`/path/to/project_root/lib/index.js`を参照するようになっています。この状態では使いにくいので、`index.js`を分割します。

`/path/to/project_root/visible/searchword`配下のファンクションを分割します。
index.jsをコピーしてリネームします。

    $ cp /path/to/project_root/index.js /path/to/project_root/searchword.js

`/path/to/project_root/visible/searchword/handler.js`を以下のように編集します

```js:handler.js
// Require Logic
var lib = require('../lib/searchword.js');
```

## DynamoDB
CloudFormationから起動します。`/path/to/project_root/s-resources-cf.json`に以下を記述してテーブルを定義します。

```json:s-resources-cf.json
"ProductSerarchTotalvalueDynamoDBTable" : {
      "Type" : "AWS::DynamoDB::Table",
      "Properties" : {
        "AttributeDefinitions" : [
          {
            "AttributeName" : "SearchWord",
            "AttributeType" : "S"   
          },
          {
            "AttributeName" : "Date",
            "AttributeType" : "S"
          }
        ],
        "KeySchema" : [
          {
            "AttributeName" : "SearchWord",
            "KeyType" : "HASH"
          },
          {
            "AttributeName" : "Date",
            "KeyType" : "RANGE"
          }
        ],
        "ProvisionedThroughput" : {
          "ReadCapacityUnits" : "5",
          "WriteCapacityUnits" : "5"
        },
        "TableName" : "${project}-${stage}-ProductSerarchTotalvalue"
      }
    }
  }
```

LambdaからDynamoDBにアクセスできるようにIAMポリシーも追加

```json:s-resources-cf.json
"PolicyName": "${stage}-${project}-lambda",
"PolicyDocument": {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:${region}:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "*"
      ],
      "Resource": "arn:aws:dynamodb:${region}:*:table/${project}-${stage}-ProductSerarchTotalvalue"
    }
  ]
},
"Roles": [
  {
    "Ref": "IamRoleLambda"
  }
]
```

## AWSへのデプロイ
CloudFormationを以下のコマンドで実行してIAMとDynamoDBをAWS上に展開

    $ serverless resources deploy

API Gateway、Lambdaをデプロイ

    $ serverless dash deploy