SERVERLESSフレームワークv1.0正式リリース版を触ってみた

# 追記
（2016/11/09）
SERVERLESSフレームワークでのデプロイのデフォルトがLAMBDAからLAMBDA_PROXYに変更されていました。それに伴い文章の修正を行いました。画像の差し替えはできていません。また、[この記事](http://qiita.com/kimama1997/items/7bbd6cb15d3c9d18792d)を見て注意書きを増やしました。

# はじめに
ついに、[SERVERLESS](https://serverless.com/)フレームワークが正式リリースされました！👏
少し反応が遅れてしまい、すでにv1.0.3（2016/10/24現在）になっていましたが、触ってみたのでまとめました。ちなみに前回のRC版の触ってみたの記事は[こちら](http://qiita.com/drafts/fc6bbb3ef99ef6190ca6)です。

## この記事のゴール
AWSと組み合わせてAPIをデプロイするところまで使ってみます。

AWSでは、API GatewayとLambdaを組み合わせてWebAPIを作成できます。それをSERVERLESSフレームワークを通してコマンド一つで簡単にデプロイできるようになります。このフレームワークを活用することで、デプロイ周りの面倒なことから開放され、APIの処理の内容に集中できるのではないでしょうか。とにかく便利です。

今回新たにinstallコマンドができ、すでに[テンプレートがいくつか公開](https://github.com/serverless/serverless/blob/master/README.md#services)されています。この調査も是非したい。

# 実施環境

- serverless v1.0.3
- node v6.7.0（v4以上が必要）
- npm v3.10.4
- OSX

# 環境構築
## 必要なもの
node、npm、aws-cli、awsアカウントが必要です。これらの導入方法は一番下のセクションに書いておきました。前の3つは下記コマンドをターミナルで叩いて反応すれば大丈夫。

- node -v
- npm -v
- aws --version

## SERVERLESSインストール

```
sudo npm install -g serverless
```

このコマンドを叩くとSERVERLESSがグローバルインストールされます。`serverless --v`でバージョンが表示されれば、無事インストールされています。

# SERVERLESSフレームワークの活用
と、その前に、様々なことを`serverless`コマンドを経由します。ですが、非常に長ったらしいので、下記エイリアスのどちらかを活用してください。slsを使うのが無難ですかね。

- sls
- slss

## 雛形の作成
ターミナルで下記を行ってください。

```bash
$ mkdir slstest
$ cd slstest
$ sls create --template aws-nodejs --name testapi
```

`--template`オプションで、雛形の種類を指定（必須）することで、サービスの雛形を作成できます。SERVERLESSでは1つのAPI Gatewayあたり1つのサービスが対応しているようです。
`--name`オプションでは、サービスの名前を指定できますが、ここでは必須ではありません。serverless.ymlから変更することが可能です。ちなみに、サービスの名前はAWSコンソールでのAPI Gatewayの名前になります（プレフィックスとしてステージ名がつきますが）。

```bash
$ sls create --template [aws-nodejs | aws-python | aws-java-maven | aws-java-gradle | aws-scala-sbt]
```

Node.jsやpythonやJavaが選べるみたいです。Lambdaが対応している言語ですね。rc版とは異なり、scalaが追加されています。今回はNode.jsを使います。Azureの場合はどうするんでしょうかね、公式ドキュメントに全く記載がなくてわかりませんでした。

雛形として生成されるファイルは下記の通りです。

```
slstest
|-- .npmignore                                                                                                                                 
|-- event.json                                                                                                                                 
|-- handler.js                                                                                                                                 
`-- serverless.yml  
```

- event.json
  - invoke（ローカルでAPIを叩く）時に利用します。APIに渡すJSONパラメータですね。
- handler.js
  - これはAWSのLambdaにあたり、ここにAPIの処理を書きます。パラメータなどの情報がeventオブジェクトに詰めて渡されます。それをうまくパースして、処理を行い、cb関数の第2引数にレスポンスのJSONを渡してあげます。第1引数にレスポンスを詰めて渡すと、異常系の終了（400〜）として扱われます。詳しくは[こちら](http://qiita.com/seiya_orz/items/3ea0bc1d93f6f5204d69)。
  - どうでもいいですが、RC以前のものと、自動で生成される処理の内容が変わっていますね。statusCodeの記述等が増えています。
- serverless.yml
  - API Gatewayの設定を書きます。APIの名前や、どのようなFunctionを作るか、ステージングなどの設定を書きます。
  - 個人的にはYAMLなのが辛い。そのうちJSONにも対応するってどこかに書いてありました。はよ。

## APIの設定（Gatewayの設定）
serverless.ymlを編集します。せっかくなのでREST APIっぽくします。YAMLはインデントが命なので、気をつけてください。

```yaml:serverless.yml
# 不要なコメントは消しています
service: testapi # API Gatewayの名前

provider:
  name: aws
  runtime: nodejs4.3
  stage: dev # ステージング名
  region: us-east-1
  memorySize: 128 # SERVERLESS FWのデフォルトは1024MBなので注意。最小は128MB。

functions:
  # AWSコンソールでのLambdaの名前、わかりやすいのをつけるとよい
   user:
     # handler.jsのuserモジュールが呼ばれる
     # handler.jsをfunctionsディレクトリに入れたりする場合はfunctions/handler.userとする
     handler: handler.user
     events:
       # endpointの作成
       - http:
           # pathには例えば、v1/api/userとかもできる
           path: user
           method: get
           cors: true
       - http:
           path: user
           method: post
           cors: true

# ちなみにこんな風にも書けます
#functions:
#  getuser:
#    handler: handler.user
#    events:
#      - http:
#          path: user
#          method: get
#          cors: true
#  # このように書くとLambdaが2つできる
#  postuser:
#    handler: handler.user
#    events:
#      - http:
#          path: user
#          method: post
#          cors: true
```

## APIの処理内容を書く
handler.jsを修正します。

### LAMBDA_PROXYを使う

```js:handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);
  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
```

LAMBDA_PROXYとは、API Gatewayの設定で、リクエストの際の様々な情報（パス、クエリストリング、HTTPメソッド、ソースIPなどなど）をeventにJSONオブジェクトとして詰め込んでくれるものです。非常に便利。

レスポンスを返す際には、callback関数の第2引数にレスポンスボディを渡します。しかし、これには注意点があって、レスポンスボディの形が決められています。必ず、`statusCode`と`body`が必要で、しかも`body`はStringである必要があります。よって、利用する際には、返したいレスポンスボディを文字列化してbodyに渡しましょう。

### 使わない場合
SERVERLESS FWではLAMBDA_PROXYの使用を推奨しているので使わないのが吉かと。特に、GETの場合、eventにクエリストリングを渡すためのマッピングの設定をする必要があります。結構面倒なのでここでは割愛。

## デプロイ
めちゃくちゃ簡単です。

```bash
$ sls deploy
Serverless: Uploading service .zip file to S3...                                                                                               
Serverless: Updating Stack...                                                                                                                  
Serverless: Checking Stack update progress...                                                                                                  
.......................................                                                                                                        
Serverless: Stack update finished...                                                                                                           
                                                                                                                                               
Service Information                                                                                                                            
service: apitest                                                                                                                               
stage: dev                                                                                                                                     
region: us-east-1                                                                                                                              
endpoints:                                                                                                                                     
  GET - https://hogehoge.execute-api.us-east-1.amazonaws.com/dev/user                                                                        
  POST - https://hogehoge.execute-api.us-east-1.amazonaws.com/dev/user                                                                       
functions:                                                                                                                                     
  apitest-dev-getuser: arn:aws:lambda:us-east-1:0000000000000:function:apitest-dev-getuser                                                      
  apitest-dev-postuser: arn:aws:lambda:us-east-1:0000000000000:function:apitest-dev-postuser
```

これでデプロイができました。AWSコンソールのAPI Gatewayを見てみると、こんな感じになっているかと。（2016/11/09 追記：統合リクエストのタイプはLAMBDA_PROXYになっているはずです）
<img width="1696" alt="スクリーンショット 2016-09-08 0.15.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/74853/b9a99c36-9222-1c05-f28b-e430184db8d0.png">

## 疎通確認
GETは、ブラウザからendpointにアクセスしてみてください。cbの第2引数のオブジェクトが表示されているはずです。試しに、URLに?id=10をつけてみてください。v0系までは、GETの場合リクエストテンプレートなどを設定しなければ、eventにパラメータが渡せなかったのですが、v1からは何もしなくても、eventオブジェクトの終わりの方のqueryに格納されていることが確認できるかと思います。これは、SERVERLESSフレームワークがデプロイ時にAPI Gatewayの統合リクエストの本文マッピングテンプレートにマッピングコードを記載してくれているためです。初心者に非常に優しいですね。


# まとめ
「非常に簡単にWebAPIが作れるSERVERLESSフレームワークのv1の触ってみた」でした。RC版とほとんど違いがありませんでしたね。

今後は、`sls install`の調査をしてみたいと思います。

# セットアップ
必要なのは以下。
- AWSアカウント
- node
- aws-cli
- serverless v1.0

以下は、インストール方法です。すでに入っている人は飛ばしてください。AWSのアカウントは、適当なユーザ作って、Administratorポリシーをアタッチしておいてください。Administratorじゃなくていいじゃんと思いますが、現状ではAdministratorじゃないと動かないみたいです。正式リリース時に必要なポリシーを列挙してくれることを期待。

## Macの方
### nodeインストール
下記手順に従ってインストール
http://www.websuppli.com/nodejs/424/

### aws-cliインストール
※Python 2.6.5以降必要。入ってなければインストール
1. curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
2. sudo python get-pip.py
3. sudo pip install awscli

## Windowsの方
動作試してません。

### nodeインストール
nodistを入れます。
1. https://github.com/marcelklehr/nodist/releases/tag/v0.7.2からダウンロード、インストール。
2. パス通す（設定されてたらスキップ）
3. 環境変数のPathにbinまでのパス
4. 環境変数のNODIST_PREFIXを新規追加しでnodistまでのパス
5. コマンドラインでnodist update実行

### aws-cliインストール
https://aws.amazon.com/jp/cli/
こっからインストーラ落としてインストール。