sbt-aws-serverlessプラグインを作った

[Serverless Architecture](http://martinfowler.com/articles/serverless.html) を、AWS上に構築するにあたり、sbt-pluginを作った。

sbt-aws-serverless
https://github.com/yoshiyoshifujii/sbt-aws-serverless

# 開発の経緯

すでに npm 版のServerless Architecture構築の補助ツールは世に出ており、Node.jsやPython、Javaをサポートしているとのこと。

* https://serverless.com/
* https://github.com/serverless/serverless

ただ、ScalaでServerless Architectureを、AWS上に構築したいよねってあたりで、じゃあ、sbt-pluginでしょってことになり、いっちょ作ってみますかということで、作った次第です。

# 設計思想

sbt-pluginを組み込んでいただき、 [Amazon API Gateway](https://aws.amazon.com/jp/api-gateway/) と、 [AWS Lambda](https://aws.amazon.com/jp/lambda/) に少ないステップで開発したコードを環境構築することを目指しています。

# 使いかた

[README](https://github.com/yoshiyoshifujii/sbt-aws-serverless/blob/master/README.md) に記載のとおりだが、ここにも書きます。

## インストール

`project/plugins.sbt` に以下を記載してください。

```scala:project/plugins.sbt
lazy val root = project.in(file(".")).dependsOn(githubRepo)

lazy val githubRepo = uri("git://github.com/yoshiyoshifujii/sbt-aws-serverless.git#master")
```

※ `#master` となっている箇所は、今後、リリースタグを切っていきますが、現状は、作ったところなので、masterブランチを指定しています。

## build.sbt

sbt-aws-serverlessプラグインは、基本的に、sbtをマルチプロジェクトで作っていただくのが良いなーと想定しています。

理由は、Serverless Architectureでサーバ構成を作るのであれば、複数のAWS Lambdaを作ってAPI Gatewayで結合していくかなーと想定しているからです。

ですので、 sbt のマルチプロジェクトについて、 [sbt Reference Manual — マルチプロジェクト・ビルド](http://www.scala-sbt.org/0.13/docs/ja/Multi-Project.html) を一読されることを推奨します。

```scala:build.sbt
lazy val root = (project in file(".")).
  enablePlugins(AWSApiGatewayPlugin)

lazy val module1 = (project in file("./modules/module1")).
  enablePlugins(AWSServerlessPlugin)

lazy val module2 = (project in file("./modules/module2")).
  enablePlugins(AWSServerlessPlugin)
```

といった具合にbuild.sbtを記載いただくと良いと想定しています。

## AWSApiGatewayPluginのコンフィグ

API Gatewayを作ったり、swagger.yamlを適用したりと操作するために、以下のコンフィグをbuild.sbtに設定します。

https://github.com/yoshiyoshifujii/sbt-aws-serverless/blob/master/README.md#awsapigatewayplugin

| sbt setting                   | Description                                               |
|-------------------------------|-----------------------------------------------------------|
| awsRegion                     | 構築するAWSのRegion(us-east-1とか、ap-northeast-1)                 |
| awsAccountId                  | AmazonアカウントID                                        |
| awsApiGatewayRestApiId        | API GatewayのRest API ID。最初は、空文字でも良い。              |
| awsApiGatewayYAMLFile         | `awsApiGatewayRestApiId` に設定したRest APIに流し込むYAMLファイルのパス |
| awsApiGatewayStages           | Seq[(String, Option[String])]で、 Stage名とDescriptionを指定する。                       |
| awsApiGatewayStageVariables   | ステージ変数を設定する。                   |

## AWSServerlessPluginのコンフィグ

LambdaをDeployしたり、API GatewayのResourceに統合リクエスト・レスポンスをマッピングしたりするために、以下のコンフィグをbuild.sbtに設定します。

https://github.com/yoshiyoshifujii/sbt-aws-serverless/blob/master/README.md#awsserverlessplugin

| sbt setting                               | Description                                                                 |
|-------------------------------------------|-----------------------------------------------------------------------------|
| awsLambdaFunctionName                     | Lambdaのファンクション名              |
| awsLambdaDescription                      | 説明。                                 |
| awsLambdaHandler                          | クラスパス。         |
| awsLambdaRole                             | Lambdaを実行するIAM Role。                             |
| awsLambdaTimeout                          | LambdaのTimeout時間。 |
| awsLambdaMemorySize                       | Lambda実行時のメモリサイズ。                |
| awsLambdaS3Bucket                         | LambdaにJARをアップロードするときに挟むS3のバケット名。              |
| awsLambdaDeployDescription                | LambdaにDeployするときの短い説明。                         |
| awsLambdaAliasNames                       | LambdaのAlias名。                                        |
| awsApiGatewayResourcePath                 | ResourceのPath。(ex. /hellos)                                           |
| awsApiGatewayResourceHttpMethod           | HTTPメソッド。(ex. GET)                          |
| awsApiGatewayResourceUriLambdaAlias       | Resourceから実行されるLambdaのURIのAliasに入れる値。     |
| awsApiGatewayIntegrationRequestTemplates  | 統合リクエストでマッピングするVelocity Template                                     |
| awsApiGatewayIntegrationResponseTemplates | 統合レスポンスのテンプレート。                         |

## swagger.yaml

Serverless Architectureを実現していく際に、API Gatewayを使用しますので、 `swagger.yaml` を作っていただき、APIを定義していくことを想定しています。

```yaml:swagger.yaml
---
swagger: "2.0"
info:
  version: "0.1"
  title: "sample-serverless"
schemes:
- "https"
paths:
  /hellos:
    get:
      consumes:
      - "application/json"
      produces:
      - "application/json"
      responses:
        200:
          description: "success"
          schema:
            $ref: "#/definitions/Hellos"
        408:
          description: "timed out"
        500:
          description: "internal server eorror"

definitions:
  Hellos:
    type: object
    required:
      - items
    properties:
      items:
        type: array
        items:
          $ref: '#/definitions/Hello'
  Hello:
    type: object
    required:
      - message
    properties:
      message:
        type: string
```

## API GatewayにREST APIを作成する

まずは、API GatewayにAPIの枠を作成しましょう。

```sh
$ sbt createApiGateway <name> [description]
ApiGateway created: xxxxxxxxxx
```

で、任意の名称と説明を作成します。

`xxxxxxxxxx` は、REST API IDが表示されます。
このIDをbuild.sbtの `awsApiGatewayRestApiId` に設定します。

## swaggerをREST APIにputする

以下のコマンドを実行し、API GatewayにResoucesをPutします。

```sh
$ sbt putApiGateway
```

## LambdaにDeployする

LambdaにDeployするには、以下のコマンドを実行します。

```sh
$ sbt deploy
```

## API GatewayにDeployする

`awsApiGatewayStages` に設定したStageを一気にDeployするには、以下のコマンドを実行します。

```sh
$ sbt deployStages
```

`awsApiGatewayStageVariables` の内容も見て適用します。

## dev環境を作る

開発中に、ちょっとLambdaとAPI Gatewayで動作確認をしたいときは、以下のコマンドを実行します。

```sh
$ sbt
> deployDev
Lambda Deploy: arn:aws:lambda:<region>:<accountId>:function:<functionName>
Create Alias: arn:aws:lambda:<region>:<accountId>:function:<functionName>:dev
[success]

> createDeployment dev
[success]
```

すると、API GatewayのStageに `dev` が、各LambdaのAliasに `dev` ができます。

# まとめ

ざっと、使い方を説明しました。

まだ、作りたてで、いろいろと機能が足りていませんが、徐々に増やしていきます。

また、今日、投稿した以外にも状況を確認できるコマンドで、 `getStages` や `getDepoyments` 、 `listLambdaVersions` 、 `listLambdaAliases` といったそれなりに使いたくなるコマンドも用意しているのですが、そのあたりの説明を割愛しています。

ドキュメントも徐々に揃えていきたいと考えています。

以上です。