SAM Local (Beta)が発表されローカル環境でサーバレスアプリケーションをデバッグできるようになったので試してみました。 ちなみにリンク先の記事はそのままでは動かそうとすると情報が足りなかったので、試したい人はGitHubの方のチュートリアルやサンプルを触ってみるのが良いと思います。
ローカルにLambdaを作成
チュートリアル用のHelloWorld関数をローカルに作ってみます。
template.yml
AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: A simple Hello World Serverless project
Resources:
HelloWorld: # <-- 関数の論理ID
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs6.10
Handler: index.handler
index.js
exports.handler = (event, context, callback) => {
console.log('LOG: Name is ' + event.name);
callback(null, "Hello " + event.name);
}
event.json
{
"name": "Yuto"
}
実行結果
# `HelloWorld` は関数の論理ID
$ sam local invoke HelloWorld -e event.json
...(省略)...
"Hello Yuto"
HelloWorldをAPI Gatewayに対応させる
sam local start-api でAPI Gatewayが起動しますが、上の設定のまま実行するとAPIの定義が足りなくてエラーになります。
$ sam local start-api
...(省略)...
ERROR: None of the Serverless functions in your SAM template have valid API event sources.
Lambda関数の設定に
Events を追加します。
Type: Api でAPI GatewayのAPIの定義になります。
...(省略)...
HelloWorld:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs6.10
Handler: index.handler
Events:
Api:
Type: Api
Properties:
Path: /hello
Method: get
Events の設定を追加すると Path に指定したpathにAPI Gatewayがデプロイされます。
$ sam local start-api
...(省略)...
Mounting index.handler (nodejs6.10) at http://127.0.0.1:3000/hello [GET]
APIを呼ぶとLambda関数が呼ばれるのですが以下のエラーが出ます。
$ curl http://localhost:3000/hello
...(省略)...
ERROR: Function HelloWorld returned an invalid response (must include one of: body, headers or statusCode in the response object)
API GatewayのProxy Integrationを使用しているため statusCode がないとエラーになるそうです。
レスポンスに
statusCode を追加します。
exports.handler = (event, context, callback) => {
console.log('LOG: Name is ' + event.name);
// callback(null, "Hello " + event.name);
callback(null, {
statusCode: 200,
body: "Hello " + event.name
});
}
ここまでで実行には成功しますが
event.name が undfined となってしまいます。
$ curl http://localhost:3000/hello
Hello undefined
APIにパラメータを渡す
curlで渡したデータはAPI Gatewayのイベントでラップされるので、API Gatewayのイベントをパースして使用する必要があります。
post も使いたい場合はAPIの定義を get から any に変更します。
get と post を両方マッピングする方法が見つからなかったので。
(2個定義すれば良いのかもですが今回はお試しなので簡単にanyで)
...(省略)...
Api:
Type: Api
Properties:
Path: /hello
Method: any
ソースコードもGET/POSTの両方に対応するよう修正します。
const parse_event = {
"GET": (event) => event.queryStringParameters,
"POST": (event) => JSON.parse(event.body)
}
exports.handler = (event, context, callback) => {
const $event = parse_event[event.httpMethod](event);
console.log('LOG: Name is ' + $event.name);
callback(null, {
statusCode: 200,
body: "Hello " + $event.name
});
}
$ curl http://localhost:3000/hello?name=Yuto
Hello Yuto
$ curl -d '{"name": "Yuto"}' http://localhost:3000/hello
Hello Yuto
まとめ
ホットリロードはソースの更新の度に行われるのではなくAPIの呼び出し毎にソースを読み込み直しているような動きをしているのでそこまでサクサク開発できないんじゃないかなという印象です。
サーバレスのアプリケーションをローカルでデバッグできるだけで楽といえば楽ですが、呼び出しに5秒くらいかかるので1画面で複数のAPIを呼び出すような場合は結構待たされると思います。
また、ホットリロードによりLambda関数のソース変更は再起動不要ですが、MethodをGETからPOSTに変更してみましたが反映されなかったのでAPIの定義を更新するには再起動が必要みたいです。
松木佑徒