AWS CDK(v2): Lambda と APIGateway を連携させる
よく使う組み合わせなのに、管理画面で設定するとややこしいのが Lambda と APIGateway なのではないかと思います。 これが簡単に書けるだけでもかなり嬉しいです。 また、Lambda を TypeScript で書く場合、TypeScript の Transpile や node modules の Install なども自動で行ってパッケージ化してくれるのでかなり使いやすいです。
事前準備
以下の準備がされているものとします。
Version
node
:16.13.1
aws-cdk
:2.2.0
tsc
:4.5.4
cowsay サンプルアプリケーション
npm の cowsay
を使って、リクエストされた文字列を牛がしゃべるテキストにして返すアプリケーションを作ってみることにします。
_____________
< Let's Start >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Setup CDK
まずディレクトリを作成して、cdk init --language typescript
をします。
これで色々雛形が作成されます。
% mkdir cow_say
% cd cow_say
% cdk init --language typescript
lib/cow_say-stack.ts
に CowSayStack
用のファイルが作られるので、最終的にはここに色々書いていきます。
/// lib/cow_say-stack.ts
import { Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class CowSayStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
// example resource
// const queue = new sqs.Queue(this, 'CowSayQueue', {
// visibilityTimeout: cdk.Duration.seconds(300)
// });
}
}
今回は先に Lambda Function を作ってから、Stask の構成を書いていきます。
Lambda Function を作る
cowsay
を Install します。
% npm install cowsay
Lambda の Handler ファイルはどこに置いても良いのですが、 lib/lambda/main.ts
に書くとします。
コード自体はシンプルです。
API Gateway からの GET
リクエストの QueryString パラメータの text
の値を cowsay
で変換して そのまま返すというものになります。
/// lib/lambda/main.ts
import * as cowsay from "cowsay";
export const handler = async (event: any = {}): Promise<any> => {
try {
let statusCode = 200;
const text = event.queryStringParameters?.text ?? "Hello!";
const said = cowsay.say({ text: text });
return { statusCode: statusCode, body: said };
} catch (error) {
console.log(error);
return { statusCode: 500, body: JSON.stringify({ message: `${error}` }) };
}
};
UnitTest
Lambda のテストの良い書き方はわからなかったですが、最初から jest
が入っているので例えば以下のようにすると UnitTest を実行できます。
/// test/lambda/main.test.ts
import * as main from "../../lib/lambda/main";
test("call handler", async () => {
const event = {
queryStringParameters: { text: "Hello!" },
};
const response = await main.handler(event);
expect(response.statusCode).toBe(200);
console.log(response.body);
});
npm run test
でも実行できますし、
VSCode だとクリックするだけで特定のテストを実行できます。
Stack 構成を記述する
今回は、APIGateway から Lambda を呼べれば良いので以下のように書けば OK です。 ポイントは NodejsFunction という NodeJS 用のを使うと、TypeScript の Transpile や node module も含めたパッケージ化をよしなにやってくれるというところです。
/// lib/cow_say-stack.ts
import { Stack, StackProps } from "aws-cdk-lib";
import { LambdaIntegration, RestApi } from "aws-cdk-lib/aws-apigateway";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Construct } from "constructs";
import * as path from "path";
export class CowSayStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// https://aws.amazon.com/jp/blogs/news/lambda-managed-by-cdk/
// For only NodeJS, Golang and Python now
const cowLambda = new NodejsFunction(this, "CowSay", {
entry: path.join(__dirname, "./lambda/main.ts"),
handler: "handler",
});
// setup API Gateway for aaLambda
const api = new RestApi(this, "CowSayAPI", {
restApiName: "CowSayAPI",
});
const integration = new LambdaIntegration(cowLambda);
api.root.addMethod("GET", integration);
}
}
Stack を Deploy する
% cdk deploy
とすると、数分でデプロイされます。
実行してみる
curl
で実行してみます。
% curl "https://umh9ezyai2.execute-api.ap-northeast-1.amazonaws.com/prod/?text=Hey"
{"message":"Error: ENOENT: no such file or directory, open '/var/cows/default.cow'"}
すると、エラーが出てしまいました。
/var/vows/default.cow
というファイルが無い、と。
import でエラーが出ているわけではないのでどうやら cowsay
の JS ファイルはパッケージに含まれているが、default.cow
というリソースファイルが含まれていないようです。
そこで bundling.nodeModules
Option で、cowsay
を追加してみます。
/// lib/cow_say-stack.ts
...
const cowLambda = new NodejsFunction(this, "CowSay", {
entry: path.join(__dirname, './lambda/main.ts'),
handler: "handler",
// Add This!
bundling: {
nodeModules: ["cowsay"],
}
});
...
もう一度デプロイします。Lambda Function だけ更新したい場合は --hotswap
という Option をつけると高速に更新できます。
ただし、あまり動作保証しないので、開発環境とかだけにしなさいと書かれています。
cdk deploy --hotswap
もう一度、curl
でアクセスしてみます。
% curl "https://umh9ezyai2.execute-api.ap-northeast-1.amazonaws.com/prod/?text=Hey"
_____
< Hey >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
今度は無事に表示されました。
さいごに
Lambda と API Gateway を使うアプリケーションを配備してみました。 最初は少し大変かもしれませんが、慣れるとちゃちゃっと作れますし、全てがコードで管理できるのでメンテやチームでの運用も楽です。 こういうのは、実際に手を動かすといろいろ理解が進みますね。