はじめに
- API Gateway、EventBridege、Webhookから呼び出すLambda関数が増えてきたので、デバッグしやすい環境をつくりなおす
手順
必要なツールのインストール
- AWS CLI
- AWS SAM CLI (Serverless Application Model CLI)
- Docker
プロジェクトの初期化
AWS SAM CLIを使ってプロジェクトを作成します。
% sam init
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
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 - GraphQLApi Hello World Example
11 - Full Stack
12 - Lambda EFS example
13 - Serverless Connector Hello World Example
14 - Multi-step workflow with Connectors
15 - DynamoDB Example
16 - Machine Learning
Template: 1
Use the most popular runtime and package type? (python3.13 and zip) [y/N]: N
Which runtime would you like to use?
1 - dotnet8
2 - dotnet6
3 - go (provided.al2)
4 - go (provided.al2023)
5 - graalvm.java11 (provided.al2)
6 - graalvm.java17 (provided.al2)
7 - java21
8 - java17
9 - java11
10 - java8.al2
11 - nodejs22.x
12 - nodejs20.x
13 - nodejs18.x
14 - python3.9
15 - python3.8
16 - python3.13
17 - python3.12
18 - python3.11
19 - python3.10
20 - ruby3.3
21 - ruby3.2
22 - rust (provided.al2)
23 - rust (provided.al2023)
Runtime: 12
What package type would you like to use?
1 - Zip
2 - Image
Package type: 1
Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.
Select your starter template
1 - Hello World Example
2 - Hello World Example TypeScript
Template: 1
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: N
Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]:
Would you like to set Structured Logging in JSON format on your Lambda functions? [y/N]:
Project name [sam-app]: shopify-lambda-api
Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)
-----------------------
Generating application:
-----------------------
Name: shopify-lambda-api
Runtime: nodejs20.x
Architectures: x86_64
Dependency Manager: npm
Application Template: hello-world
Output Directory: .
Configuration file: shopify-lambda-api/samconfig.toml
Next steps can be found in the README file at shopify-lambda-api/README.md
Commands you can use next
=========================
[*] Create pipeline: cd shopify-lambda-api && sam pipeline init --bootstrap
[*] Validate SAM template: cd shopify-lambda-api && sam validate
[*] Test Function in the Cloud: cd shopify-lambda-api && sam sync --stack-name {stack-name} --watch
作成後のディレクトリ構造
shopify-lambda-api/
./template.yaml
./hello-world/.npmignore
./hello-world/tests/unit/test-handler.mjs
./hello-world/package.json
./hello-world/app.mjs
./README.md
./.gitignore
./samconfig.toml
./events/event.json
./template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
shopify-lambda-api
Sample SAM Template for shopify-lambda-api
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs20.x
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
./hello-world/tests/unit/test-handler.mjs
'use strict';
import { lambdaHandler } from '../../app.mjs';
import { expect } from 'chai';
var event, context;
describe('Tests index', function () {
it('verifies successful response', async () => {
const result = await lambdaHandler(event, context)
expect(result).to.be.an('object');
expect(result.statusCode).to.equal(200);
expect(result.body).to.be.an('string');
let response = JSON.parse(result.body);
expect(response).to.be.an('object');
expect(response.message).to.be.equal("hello world");
});
});
./hello-world/app.mjs
/**
*
* Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
* @param {Object} event - API Gateway Lambda Proxy Input Format
*
* Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
* @param {Object} context
*
* Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
* @returns {Object} object - API Gateway Lambda Proxy Output Format
*
*/
export const lambdaHandler = async (event, context) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello world',
})
};
return response;
};
./samconfig.toml
# More information about the configuration file can be found here:
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
version = 0.1
[default.global.parameters]
stack_name = "shopify-lambda-api"
[default.build.parameters]
cached = true
parallel = true
[default.validate.parameters]
lint = true
[default.deploy.parameters]
capabilities = "CAPABILITY_IAM"
confirm_changeset = true
resolve_s3 = true
[default.package.parameters]
resolve_s3 = true
[default.sync.parameters]
watch = true
[default.local_start_api.parameters]
warm_containers = "EAGER"
[default.local_start_lambda.parameters]
warm_containers = "EAGER"
./events/event.json
{
"body": "{\"message\": \"hello world\"}",
"resource": "/{proxy+}",
"path": "/path/to/resource",
"httpMethod": "POST",
"isBase64Encoded": false,
"queryStringParameters": {
"foo": "bar"
},
"pathParameters": {
"proxy": "/path/to/resource"
},
"stageVariables": {
"baz": "qux"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, sdch",
"Accept-Language": "en-US,en;q=0.8",
"Cache-Control": "max-age=0",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Custom User Agent String",
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"requestContext": {
"accountId": "123456789012",
"resourceId": "123456",
"stage": "prod",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"requestTime": "09/Apr/2015:12:34:56 +0000",
"requestTimeEpoch": 1428582896000,
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"accessKey": null,
"sourceIp": "127.0.0.1",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "Custom User Agent String",
"user": null
},
"path": "/prod/path/to/resource",
"resourcePath": "/{proxy+}",
"httpMethod": "POST",
"apiId": "1234567890",
"protocol": "HTTP/1.1"
}
}
Lambda関数の作成
プロジェクト内にあるコードファイル(app.py
や app.js
)を編集します。
Node.jsの例 (app.js
)
exports.handler = async (event) => {
console.log("Event Received:", event);
return {
statusCode: 200,
body: "Hello from Lambda!",
};
};
テストイベントの設定
events/event.json
にテストデータを追加します。
例 (API Gateway用)
{
"httpMethod": "GET",
"path": "/hello",
"queryStringParameters": {
"name": "World"
}
}
例 (EventBridge用)
{
"source": "com.example.myapp",
"detail-type": "MyDetailType",
"detail": {
"key1": "value1"
}
}
ローカルでテスト実行
a) Lambda関数のローカル実行
テストイベントを使って関数を実行します。
sam local invoke "HelloWorldFunction" -e events/event.json
"HelloWorldFunction"
はtemplate.yaml
に定義されたLambda関数の名前です。- 出力例:
{ "statusCode": 200, "body": "Hello from Lambda!" }
b) API Gatewayのローカルエミュレーション
API Gatewayをエミュレートし、HTTPリクエストでLambdaをテストします。
sam local start-api
- デフォルトで
http://localhost:3000
にエンドポイントが作成されます。 - ブラウザやPostmanでリクエストを送信:
GET http://localhost:3000/hello?name=World
c) EventBridgeイベントのエミュレート
EventBridgeのイベントを生成してLambdaをトリガーします。
sam local generate-event eventbridge put-event \
--source "com.example.myapp" \
--detail-type "MyDetailType" \
--detail '{"key1":"value1"}' > events/eventbridge.json
sam local invoke "HelloWorldFunction" -e events/eventbridge.json
デバッグ設定
ローカルでデバッグを行うには、SAM CLIにデバッグポートを指定します。
例 (Node.jsのデバッグ)
sam local invoke -d 9229 "HelloWorldFunction"
デバッガ(VS CodeやPyCharm)を設定して、指定ポートに接続します。
本番デプロイ
開発が完了したら、SAM CLIを使ってデプロイします。
- デプロイ実行
sam deploy --guided
- プロンプトで設定
- デプロイ先リージョン(例:
us-east-1
) - スタック名(例:
my-lambda-stack
)
- デプロイ先リージョン(例:
- デプロイ結果の確認
Outputs: HelloWorldApi: Description: API Gateway endpoint URL Value: https://abc123.execute-api.us-east-1.amazonaws.com/Prod/hello/
デプロイ後、生成されたAPI GatewayエンドポイントでLambdaを呼び出せます。
まとめ
- 必要なツール(AWS CLI, SAM CLI, Docker)をインストール。
sam init
でプロジェクトを作成。- Lambda関数やテストイベントを設定。
sam local invoke
やsam local start-api
を使ってローカルでテスト。sam deploy
で本番環境にデプロイ。
これで、ローカル環境でAWS Lambdaを効率的に開発・テストするフローが構築できます!