AWS SAM CLI「sam remote invoke」コマンドでクラウド上のLambda関数をテストする
はじめに
SAM CLIのバージョン1.88.0が2023年6月23日にリリースされ、Lambda関数のリモート呼び出し機能が追加されました。これにより、クラウドにデプロイされたLambda関数をSAM CLIのコマンドsam remote invoke
でテストできるようになりました。このコマンドには様々なオプションが追加可能であり、複数の呼び出しモードがサポートされています。
レスポンスストリーミング、非同期呼び出し、ドライラン、リクエスト/レスポンスなど、複数の呼び出しモードがサポートされています。
AWS公式より引用
これまでLambda関数のテストは主にAWSコンソール画面もしくはAWS CLIを使用していましたが、新たな選択肢として、sam sync
コマンドとsam remote invoke
コマンドを組み合わせた方法が紹介されています。sam syncコマンドを使うことでローカルとリモートを同期させながら開発できるため、構築、デプロイ、テストの反復ループを効率的に高速化できます。
事前準備
sam cli
コマンドで環境構築します。
今回検証したバージョンです。
$ sam --version
SAM CLI, version 1.93.0
sam init
コマンドを使用して、テンプレートとして「Hello World Example」を選択し、言語としてGoを選びました。
$ sam init
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Choose an AWS Quick Start application template
1 - Hello World Example
2 - Data processing
3 - Hello World Example with Powertools for AWS Lambda
4 - Multi-step workflow
5 - Scheduled task
6 - Standalone function
7 - Serverless API
8 - Infrastructure event management
9 - Lambda Response Streaming
10 - Serverless Connector Hello World Example
11 - Multi-step workflow with Connectors
12 - Full Stack
13 - Lambda EFS example
14 - Hello World Example With Powertools
15 - DynamoDB Example
16 - Machine Learning
Template: 1
Use the most popular runtime and package type? (Python and zip) [y/N]: N
Which runtime would you like to use?
1 - aot.dotnet7 (provided.al2)
2 - dotnet6
3 - go1.x
4 - go (provided.al2)
5 - graalvm.java11 (provided.al2)
6 - graalvm.java17 (provided.al2)
7 - java17
8 - java11
9 - java8.al2
10 - java8
11 - nodejs18.x
12 - nodejs16.x
13 - nodejs14.x
14 - nodejs12.x
15 - python3.9
16 - python3.8
17 - python3.7
18 - python3.11
19 - python3.10
20 - ruby3.2
21 - ruby2.7
22 - rust (provided.al2)
Runtime: 3
作成されたアプリは、API GatewayとLambdaのシンプルな構成となっています。手順に従うと、「sam-app/template.yaml」ファイルにシステム構成が定義されていますので、詳細を知りたい方はこのファイルを参照してください。
sam remote invokeコマンド試す
Lambda関数
package main
import (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return events.APIGatewayProxyResponse{
Body: request.Body,
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
API Gatewayを介して送信されるリクエストに対して、返却処理を実装しています。ローカルで簡単に確認するためには、「events/events.json」ファイルにsam init
によって予め用意されているAPI Gatewayを通じてリクエストされるテストデータを利用することがおすすめです。
$ sam local invoke HelloWorldFunction --event events/event.json
↓出力結果
{"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"{\"message\": \"hello world\"}"}
ビルドとデプロイ
$ sam build --use-container
$ sam deploy --guided
sam deploy guided
コマンドを実行する際に表示される質問については、すべて「yes」またはデフォルトの回答で進行して問題ありません。
sam syncで確認
ここからは、ローカルとクラウドを同期させ、迅速にクラウド上でテストを試せる手順を体験します。まず最初に、同期を行うためのコマンドを実行します。
$ sam sync --stack-name sample-app --watch
同期が完了したら、テストを実行します。
テストデータが「events/event.json」に用意されていますので、コマンドのオプションでそれを使用して確認します。
$ sam remote invoke HelloWorldFunction --stack-name sam-app --event-file events/event.json
Invoking Lambda Function HelloWorldFunction
START RequestId: 7ef6f15f-6194-43d7-8252-359abdc7b0a2 Version: $LATEST
END RequestId: 7ef6f15f-6194-43d7-8252-359abdc7b0a2
REPORT RequestId: 7ef6f15f-6194-43d7-8252-359abdc7b0a2 Duration: 21.95 ms Billed Duration: 22 ms Memory Size: 128 MB Max Memory Used: 30 MB
{"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"{\"message\": \"hello world\"}"}%
値が正しく出力されていることを確認できました。
ローカルでの修正をクラウド上ですぐに確認する手応えを感じるために、Lambda関数を修正します。
修正内容は、返却部分にリクエスト時間を含めるようにすることです。
package main
import (
"fmt"
"time"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
formattedTime, err := formatRequestTime(request.RequestContext.RequestTime)
if err != nil {
return errorResponse(err), nil
}
responseBody := fmt.Sprintf("requestTime:%v, body: %v", formattedTime, request.Body)
return successResponse(responseBody), nil
}
func formatRequestTime(t string) (string, error) {
const inputLayout = "02/Jan/2006:15:04:05 -0700"
parsedTime, err := time.Parse(inputLayout, t)
if err != nil {
return "", err
}
const outputLayout = "2006/01/02 15:04" // YYYY/mm/dd HH:ii 形式
return parsedTime.Format(outputLayout), nil
}
func errorResponse(err error) events.APIGatewayProxyResponse {
return events.APIGatewayProxyResponse{
Body: err.Error(),
StatusCode: 500,
}
}
func successResponse(body string) events.APIGatewayProxyResponse {
return events.APIGatewayProxyResponse{
Body: body,
StatusCode: 200,
}
}
func main() {
lambda.Start(handler)
}
ローカルでコードを変更して保存すると、数秒でAWS上のLambda関数にも変更が反映されます。
Syncing Lambda Function HelloWorldFunction...
Cache is invalid, running build and copying resources for following functions (HelloWorldFunction)
Building codeuri: /Users/XXXXX/go/src/github.com/XXXXX/sam-app/hello-world runtime: go1.x metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running GoModulesBuilder:Build
Updated source_hash and manifest_hash field in build.toml for function with UUID e4859b3c-1a01-4c4d-96fa-31b662f3c746
Finished syncing Lambda Function HelloWorldFunction.
修正したコードのテストを再度確認します。
sam remote invoke HelloWorldFunction --stack-name sam-app --event-file events/event.json
Invoking Lambda Function HelloWorldFunction
START RequestId: a2efc0cb-c713-4bce-91af-c6d69ae454db Version: $LATEST
END RequestId: a2efc0cb-c713-4bce-91af-c6d69ae454db
REPORT RequestId: a2efc0cb-c713-4bce-91af-c6d69ae454db Duration: 6.05 ms Billed Duration: 7 ms Memory Size: 128 MB Max Memory Used: 30 MB
{"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"requestTime:2015/04/09 12:34, body: {\"message\": \"hello world\"}"}%
問題なく出力されていることを確認しました。
おわりに
今回は、AWS SAM CLIのリモート呼び出し機能について説明しました。また、sam remote invoke
コマンドにはさまざまなオプションがあり、詳細を知りたい場合は公式ドキュメントをご参照ください。
Discussion