この記事は、自分のブログからの転載です。
http://selmertsx.hatenablog.com/
やりたいこと
- TypeScript で書かれている AWS Lambda のコードを AWS SAM Local で動かしたい
- TypeScriptのコードとbuild後のコードは別ディレクトリで保持したい
- AWS SAM LocalのREADMEではそこの説明が無いので、自分でなんとか動く方法を模索する必要がある
結論
CodeUri プロパティはcloudformation.ymlからの相対パスを指定する必要がある
AWS SAM Localとは
AWS Lambda関数をローカルで実行しテストができるようになるツール。
S3, DynamoDB, Kinesis 等のリソースからのイベントをエミュレートすることもできる。
API Gatewayをlocalで動かし、Lambdaコードの変更をhot reloadすることもできる。
AWS SAM のinstall
npm install -g aws-sam-local
sam --version # installできているか確認する
上記コマンドだけで installが可能。Dockerも必要なので気をつけること。
設定内容
AWS SAMの説明とcloudformation.yml の書き方についてはここに書いてあるので、ここを見ながら設定を行う。
https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
yamlの設定内容
# cloudformation.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Simple Lambda functions
Resources:
HelloWorld:
Type: AWS::Serverless::Function
Properties:
CodeUri: build/src
Handler: index.post
Runtime: nodejs6.10
Events:
GetResource:
Type: Api
Properties:
Path: /chat-bot
Method: post
上記の設定ファイルが SAM Localを使う上で、自分が設定した CloudFormationのymlである。CloudFormationに Transform: AWS::Serverless-2016-10-31
という値を追加することで、SAMの定義をCloudFormationで行うことが可能となる。
In order to include objects defined by AWS SAM within a CloudFormation template, the template must include a Transform section in the document root with a value of AWS::Serverless-2016-10-31.
ここで重要なのは HelloWorldリソースのCodeUri
プロパティで、こいつはjsファイルのディレクトリを指す。気をつけなければならないのは、指定するディレクトリパスは絶対パスか、cloudformation.ymlからの相対パスを指定しなければならないということ。よって、このときのディレクトリ構成は下記のようになる。
➜ speee_pf_checker git:(aws_saml) ✗ tree -I node_modules
.
├── build
│ └── src
│ ├── index.js
| ...
│ └── index.js.map
├── cloudformation.yml
├── package.json
├── src
│ ├── application.ts
│ ├── index.ts
| ...
│ └── pc_environment.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
ちなみにドキュメントでは下記のように記載されている。
For example, if your AWS Lambda function source code is in the /home/user/code/lambdafunction/ folder, specify
CodeUri: /home/user/code/lambdafunction
for the AWS::Serverless::Function resource. The command returns a template and replaces the local path with the S3 location: CodeUri: s3://mybucket/lambdafunction.zip.
ということで、絶対パスじゃないといけないかと思ったら、絶対パス指定して実行したら下記のエラーとなった。
➜ speee_pf_checker git:(aws_saml) ✗ echo '{"body": "chiba"}' | sam local invoke HelloWorld --template cloudformation.yml
2017/11/27 19:22:28 Successfully parsed cloudformation.yml
2017/11/27 19:22:28 Connected to Docker 1.34
2017/11/27 19:22:28 Fetching lambci/lambda:nodejs6.10 image for nodejs6.10 runtime...
nodejs6.10: Pulling from lambci/lambda
Digest: sha256:0721cee9614fe0c995c2eb0f52b9803a23d1c2da3007d46cb54b745d970850a0
Status: Image is up to date for lambci/lambda:nodejs6.10
2017/11/27 19:22:31 Reading invoke payload from stdin (you can also pass it from file with --event)
2017/11/27 19:22:31 Invoking index.post (nodejs6.10)
START RequestId: 08f01507-747c-1789-1312-b3368c5a26ad Version: $LATEST
Unable to import module 'index': Error
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
END RequestId: 08f01507-747c-1789-1312-b3368c5a26ad
REPORT RequestId: 08f01507-747c-1789-1312-b3368c5a26ad Duration: 13.31 ms Billed Duration: 0 ms Memory Size: 0 MB Max Memory Used: 29 MB
{"errorMessage":"Cannot find module '/var/task/index'","errorType":"Error","stackTrace":["Function.Module._load (module.js:417:25)","Module.require (module.js:497:17)","require (internal/module.js:20:19)"]}
JavaScriptのコード
// build/src/index.js
'use strict';
console.log('Loading function');
exports.post = (event, context, callback) => {
callback(null, {
statusCode: 200,
headers: { "x-custom-header" : "my custom header value" },
body: "Hello " + event.body
});
};
確認用のシンプルなJSコード。
動作確認
➜ speee_pf_checker git:(aws_saml) yarn build
yarn run v1.3.2
$ tsc
✨ Done in 3.25s.
➜ lambda git:(aws_saml) ✗ echo '{"body": "chiba"}' | sam local invoke HelloWorld --template cloudformation.yml
2017/11/27 18:04:54 Successfully parsed cloudformation.yml
...
{"statusCode":200,"headers":{"x-custom-header":"my custom header value"},"body":"Hello chiba"}
上記コマンドで確認した結果、aws sam localが動いていることが確認できた。
後程確認すること
- node_modulesを AWS SAM Localで読み込む
- API GatewayをLocalで使う