ちょっと話題の記事

Amazon API Gateway + LambdaのWeb APIをサクっと作るfluctを試してみた

2015.08.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
API GatewayとLambdaの組み合わせはサーバーレスでWebAPIをホストできる新しいフレームワークとして、大きな注目を集めていますね。ただ、1つのAPIを定義するためにはManagement Consoleの画面で各サービスをそれぞれ構成する必要があり、かなり手間がかかる印象です。そこで、それらの作業を簡単に行うツールとして@r7kamuraさんが開発するfluctを使ってみたいと思います。

fluctとは

GitHubのDescriptionにWeb application framework for Amazon Lambda and Amazon API Gateway.とある通り、RailsなどのWebアプリケーションフレームワーク風にAPI Gateway+Lambdaを扱うツールです。

検証環境

  • OS : MaxOS X Yosemite
  • Node.js : v0.12.4
  • npm : バージョン 2.10.1
  • fluct : バージョン 0.2.4

インストール

fluctはNode.jsで記述されており、npmでインストールします。fluctコマンドのPATHを通すために-gフラグを付けます。

$ npm install -g fluct
/usr/local/bin/fluct -> /usr/local/lib/node_modules/fluct/bin/fluct
fluct@0.2.4 /usr/local/lib/node_modules/fluct
├── commander@2.8.1 (graceful-readlink@1.0.1)
├── node-aws-lambda@0.1.4 (async@1.4.2)
├── ejs@2.3.3
├── yazl@2.2.2 (buffer-crc32@0.2.5)
├── mkdirp@0.5.1 (minimist@0.0.8)
├── glob@5.0.14 (path-is-absolute@1.0.0, inherits@2.0.1, once@1.3.2, inflight@1.0.4, minimatch@2.0.10)
├── moment@2.10.6
├── aws-sdk@2.1.44 (xmlbuilder@0.4.2, xml2js@0.2.8, sax@0.5.3)
├── amazon-api-gateway-client@0.1.3 (stackable-fetcher-aws-signer-v4@0.0.1, stackable-fetcher@0.3.0)
└── express@4.13.3 (escape-html@1.0.2, merge-descriptors@1.0.0, cookie@0.1.3, array-flatten@1.1.1, cookie-signature@1.0.6, utils-merge@1.0.0, fresh@0.3.0, range-parser@1.0.2, methods@1.1.1, vary@1.0.1, path-to-regexp@0.1.7, content-type@1.0.1, etag@1.7.0, parseurl@1.3.0, serve-static@1.10.0, content-disposition@0.5.0, depd@1.0.1, qs@4.0.0, on-finished@2.3.0, debug@2.2.0, finalhandler@0.4.0, accepts@1.2.12, type-is@1.6.6, send@0.13.0, proxy-addr@1.0.8)
$

これで準備OKです。

スケルトンファイルの生成

fluctは、Railsなどと同様に特定のディレクトリ配下にアプリケーションファイルを配置します。アプリケーションのスケルトンはfluct new <API名>で作成します。

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

APIの構成は<API名>/package.jsonファイル、APIのアクション(API GatewayのResource/Method、Lambda Function定義のセット)は<API名>/actions/ディレクトリ以下に追加していきます。アクションのスケルトンはfluct generate <アクション名>で作成します。

$ cd apisample/
$ fluct generate list_users
Created ./actions/list_users
Created ./actions/list_users/index.js
Created ./actions/list_users/package.json

<API名>/actions/<アクション名>/ディレクトリが作成され、アクションの構成を<アクション名>/package.jsonファイル、Lambda Functionの定義を<アクション名>/index.jsとして生成されます。スケルトンには、以下のようにダミーのAPI Gateway MethodとしてGET、Resourceとして/dummyがセットされます。

list_users/package.json

{
  "name": "list_users",
  "version": "0.0.1",
  "private": true,
  "fluct": {
    "contentType": "text/html",
    "httpMethod": "GET",
    "path": "/dummy"
  }
}

Lambda Functionのスケルトンは以下のようになっています。レスポンスとしてHello, world!を返す最低限の記述ですね。

list_users/index.js

exports.handler = function (event, context) {
  context.succeed('Hello, world!');
};

あとは、好みのResource/Methodに変更し、Lambda Functionにアプリケーションロジックを追加していく感じです。Lambda FunctionでNodeモジュールを利用する場合はアクションのpackage.jsonファイルにdependencyを追加しましょう *1。今回はお試しなので、そのままにしておきます。定義したアクションの一覧は、これまたRailsのようにfluct routesで一覧表示できます。

$ cd ../../
$ fluct routes
GET    /dummy #list_users
$

良い感じですね。

ローカルモード

fluctにはローカルモード(fluct server)が備わっており、デプロイ前の動作確認ができます。

$ fluct server
Server starting on http://127.0.0.1:3000

別の端末やWebブラウザからhttp://127.0.0.1:3000/<アクション名>にアクセスしてみると...

$ curl http://127.0.0.1:3000/dummy/
Hello, world!
$

Lambda Functionに記述した処理のレスポンスが返ってきますね!fluctの依存モジュールの様子から、内部でExpressが実行され、fluctのディレクトリレイアウトに合わせてルーティングされているようです。Lambda FunctionではAWS SDK for JavascriptでAWSのAPIにアクセスするケースが多いと思います。ローカルモードではローカルマシンでAWS SDKを実行するのと同様の設定でAPIキーを読み込みますので、~/.aws/credentialsファイルなどを事前に確認しておきましょう。

AWSへのデプロイ

AWSにデプロイするためには、Lambdaの実行ロールをAPIの構成ファイル(<API名>/package.json)にセットしておく必要があります。Lambda Functionで行う処理に合わせて適当なIAMポリシーを割り当てたロールのARNを確認しておきましょう。

apisample/package.json

{
  "name": "apisample",
  "version": "0.0.1",
  "private": true,
  "fluct": {
    "restapiId": null,
    "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/lambda_exec_role"
  }
}

では、アクション定義を元にAPI GatewayとLambdaの設定をデプロイするfluct deployを実行します。以下の処理が一度に実行され、結構壮観です!

  • Lambda Functionのアップロード
  • Lambda Functionメタデータ(Execute Roleの設定)
  • API Gateway APIの作成
  • API Gateway Resourceの作成
  • API Gateway Methodの作成、Lambda Event Sourceの紐付け
  • API Gateway Stageのデプロイ

なお、現時点ではLambda Functionのアップロードとメタデータ更新の処理順序の関係で、初回実行はエラーになるようです。再度実行すると正常に完了します。バージョン0.2.5で修正されました。

$ fluct deploy
Created zip: ./actions/action/lambda.zip
ResourceNotFoundException: Function not found: arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:action
    at Object.extractError (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/protocol/json.js:43:27)
    at Request.extractError (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/protocol/rest_json.js:37:8)
    at Request.callListeners (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
    at Request.emit (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
    at Request.emit (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/request.js:595:14)
    at Request.transition (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/request.js:21:10)
    at AcceptorStateMachine.runTo (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/request.js:37:9)
    at Request.<anonymous> (/usr/local/lib/node_modules/fluct/node_modules/aws-sdk/lib/request.js:597:12)
Uploaded function: action
$ fluct deploy
Created zip: ./actions/action/lambda.zip
Uploaded function: action
Created restapi: 01234567
Updated endpoint: GET /dummy
Deployed: https://01234567.execute-api.us-east-1.amazonaws.com/production
$

では、最後に表示されたAPI GatewayのエンドポイントにResourceの/dummyを付与してアクセスしてみます。

$ curl https://0usu7lppaj.execute-api.us-east-1.amazonaws.com/production/dummy
Hello, world!
$

API GatewayからLambdaがキックされ、レスポンスが返ってきました!

まとめ

LambdaとAPI GatewayをWebアプリケーションフレームワークのように扱えるツール、fluctをご紹介しました。fluctを使えばさくさくAPIを追加してアプリ開発が捗りそうですね!

fluctは早いペースで開発が進んでいるため、コマンドオプションやファイル構成が度々変更されます。試す際には最新のUsage(GitHubのREADME)をご確認ください!

参考URL

脚注

  1. npm installの実行はこの後のデプロイ時(fluct deploy)に自動実行されますが、ローカルモード(fluct server)では実行されないため、必要に応じて各アクションのディレクトリでnpm installを実行しましょう。