FluctとAPI Gateway+LambdaでWebアプリをつくる

Fluctというツールを使いながら、Amazon API GatewayとAWS Lambdaを組み合わせてWebアプリをつくる方法について説明します。JavaScriptで実装でき、自動的にそこそこスケールし、Amazon EC2などで自前のWebサーバを常時稼働させておく必要なく、基本的にはリクエスト回数と転送量に応じてのみ課金されるようなWebアプリの環境を手に入れることが目的です。

Amazon API Gatewayとは

Amazon API GatewayはWeb APIを簡単に作成・公開・管理するためのサービスです。2015年7月9日に新しく公開されました。Qiitaにも既にいくつかの記事が投稿されています。それ自身はプロキシとして振る舞い、バックエンドのサービスが提供するデータや機能にアクセスするための入口として振る舞います。

バックエンドのサービスには、AWS Lambdaか、あるいはHTTP経由でアクセスできるWebアプリケーションを指定できます。豪華なHTTPプロキシとして振る舞うという捉え方が適しているかもしれません。GET /foo などのエンドポイントを指定して、

  • どんなHTTPリクエストを許可するか
  • どのサービスにプロキシするか
  • サービスにどんな入力を渡すか
  • サービスからの出力をどうHTTPレスポンスに変換するか

などの項目を設定しておくことで、実際にHTTPリクエストが来るとそのように振る舞ってくれます。他に特筆すべき機能として、定義したエンドポイント用にAndroidやiOS用のSDKを自動生成してくれたり、複数の環境にデプロイしたりという機能がありますが、詳しくはAmazon API Gatewayの よくある質問 などを見てみてください。

Fluctとは

FluctはAmazon API GatewayとAWS Lambdaを組み合わせて1つのWebアプリをつくるのを支援するためのツールです。AWS Lambdaを使う場合はNode.jsかJava 8の環境で動くコードを書くことになるので、これに合わせてFluctはNode.jsで実装されています。Webアプリの開発者は、開発に使う環境にFluctをインストールし、fluct というコマンドを利用しながら開発を進めていくことになります。

Fluctをインストールする

Fluctは、Node.jsのパッケージ管理ツールであるnpm経由でインストールできます。FluctはNode.js v0.12以上で動作することを確認しているので、Fluctをインストールする環境にNode v0.12以上がインストールされていない場合は、まずそちらを先にインストールしてください。例えば、特に何もインストールしていない状態のMac OS XにHomebrew経由でNode.jsをインストールしたあとにFluctをインストールするには、以下のコマンドを実行します。手元の環境に合わせて適宜実行するコマンドを選んでください。

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew install node
$ npm install fluct --global

新しくアプリをつくる

Fluctを使って新しくアプリをつくってみます。fluct new <name> というコマンドを利用すれば、現在のディレクトリに新しいアプリ用のディレクトリが生成されます。

$ fluct new myapp
Created ./myapp
Created ./myapp/.gitignore
Created ./myapp/actions
Created ./myapp/actions/.keep
Created ./myapp/package.json

アプリという単位は、1つのプロジェクトの単位であり、Amazon API Gateway上での「Restapi」という単位と一致します。Restapiごとに https://{restapi}.execute-api.{region}.amazonaws.com/{stage}/ というURLが割り当てられます。このURLには独自ドメインを割り当てられます。ドメインを分けたい単位でアプリを分けるというのが良いと思います。

Actionを追加する

試しに、GET /ping にアクセスすると "pong" が返ってくるというサンプルをつくることにします。Fluctでは、この GET /ping のようなエンドポイントの単位のことをactionと呼んでいます。RailsなどのWebアプリケーションフレームワークにおける、ControllerのActionに相当する部分です。今回は、GET /ping のためにshow_pingという名前のactionをつくることにします。アプリのディレクトリで fluct generate <name> というコマンドを実行すると、actionに必要なファイル群が生成されます。

$ cd myapp
$ fluct generate show_ping
Created ./actions/show_ping
Created ./actions/show_ping/index.js
Created ./actions/show_ping/package.json

Actionのパスを変更する

Actionごとに、package.json というファイルにそのactionが担当するエンドポイントの情報が定義されています。自動生成されたファイルには GET /dummy というエンドポイントが設定されているので、これを GET /ping に変更します。

$ vi actions/show_ping/package.json
$ cat actions/show_ping/package.json
{
  "name": "show_ping",
  "private": true,
  "fluct": {
    "arn": null,
    "contentType": "text/html",
    "httpMethod": "GET",
    "path": "/ping"
  }
}

Actionの実装を変更する

Actionがリクエストを受け取ったときにどう振る舞うかは、個々のactionのindex.jsというファイルに定義されています。これは最終的にAWS LambdaにアップロードされてNode.jsで実行されることになるファイルです。context.succeedの引数がレスポンスボディになるので、これを書き換えます。

$ vi actions/show_ping/index.js
$ cat actions/show_ping/index.js
exports.handler = function (event, context) {
  context.succeed('pong');
};

IAM Roleを設定する

show_pingのパスと実装を変更したので、これをAWS LambdaとAmazon API Gatewayに反映させれば完了です。Amazon API GatewayからAWS Lambda上に置かれたshow_pingという関数を呼び出して実行することになりますが、AWSの制約上、予めshow_pingという関数にAmazon API Gatewayからの呼び出しを許可する権限を与えておかなければ実行できないようになっています。その権限管理の仕組みとしてIAM Roleを使うことになっているため、まずIAM Roleを用意する必要があります。

IAM Roleは、AWSマネジメントコンソールのIAMサービスから作成できます。AWSLambdaBasicExecutionRoleというポリシーを持ったIAM Roleを新たに作成し、そのIAM RoleのARNと呼ばれる識別子を手に入れ、Fluctのアプリのpackage.jsonに設定します。かなり面倒ですが、全てのactionで同じIAM Roleを利用するので、この作業は一度だけやれば大丈夫です。この辺、権限がある場合は自動で設定されるようにしたいですね。

$ vi package.json
$ cat package.json
{
  "name": "myapp",
  "private": true,
  "fluct": {
    "restapiId": null,
    "roleArn": "arn:aws:iam::012345678912:role/myExampleRole"
  }
}

デプロイしてみる

fluct deploy というコマンドを使えば、AWS Lambdaへのコードのアップロード、Amazon API Gateway上での設定などを全部やってくれます。このときAWSのAPIを利用しますが、AWS SDKの認証の仕組みを利用するので、~/aws/.credentials か環境変数に認証情報が設定されている必要があります。

$ fluct deploy
Created zip file: ./actions/show_ping/lambda.zip
Uploaded function: show_ping
Updated endpoint: GET /ping
Deployed: https://123ge4oabj.execute-api.us-east-1.amazonaws.com/production

動作を確認する

デプロイが問題なく完了したら、show_pingのactionが正しく動作しているか確認してみましょう。

$ curl https://123ge4oabj.execute-api.us-east-1.amazonaws.com/production/ping -i
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 13
Connection: keep-alive
Date: Tue, 11 Aug 2015 19:22:33 GMT
x-amzn-RequestId: 512f8391-405e-11e5-acef-2125b850bbe1
X-Cache: Miss from cloudfront
Via: 1.1 6145a790e7dca1c0c567e1f5decce786.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 5LvHm6SaEQnTj1ubwlCvJhew6G86AU6FFEGB2ic3FI-r7kwNfwDCXg==

pong

はい。

おわり

以上で、Fluctを使いながらAmazon API GatewayとAWS Lambdaを組み合わせてWebアプリをつくる方法はひとまずおしまいです。より詳しい使い方を見たい場合は、r7kamura/fluct の説明を見ると良いでしょう。また、サンプルアプリの r7kamura/fluct-example にはテンプレートエンジンやMarkdownパーサを利用してHTMLを描画するサンプルが用意されているので、こちらも参考になるかもしれません。