AWS CDKでサーバレスAPIをJavaで作ってみた
AWS CDKに慣れるためにJavaでCDKを書いてサーバレスAPI(Lambda + API Gateway)を作ってみました。
CDKのインストール&セットアップ
まずはCDKのインストールになります。
$ npm install -g aws-cdk
$ cdk --version
1.109.0 (build c647e38)
つづいてCDKのセットアップになります。
$ mkdir cdk_hello && cd cdk_hello
$ cdk init sample-app --language java
$ cdk bootstrap
これで各種ファイルが作成されました。あとは設定コードを書いていくだけです。
補足ですが、スイッチロールして作業を行う場合はAWS CLIと同様にcdk bootstrap --profile XX
のようにして実行可能です。
Lambda&APIGateway作成
公式のチュートリアルではLambdaを作成してからAPI Gatewayの作成という順番になっていますが、どちらも一緒に作成してしまいます。
pom.xmlに追加
software.amazon.awscdk.lambda
とsoftware.amazon.awscdk.apigateway
のライブラリを追加します。
<dependencies>
<!-- AWS Cloud Development Kit -->
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>core</artifactId>
<version>${cdk.version}</version>
</dependency>
<!-- ここから追加 -->
<!-- Respective AWS Construct Libraries -->
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>lambda</artifactId>
<version>1.109.0</version>
</dependency>
<!-- Respective AWS Construct Libraries -->
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>apigateway</artifactId>
<version>1.109.0</version>
</dependency>
<!-- ここまで -->
中略
</dependencies>
Lambdaとして動くコードを作成
$ pwd
/cdk_hello
$ mkdir lambda
$ touch lambda/hello.js
exports.handler = async function(event) {
console.log("request:", JSON.stringify(event, undefined, 2));
return {
statusCode: 200,
headers: { "Content-Type": "text/plain" },
body: `Hello, CDK! You've hit ${event.path}\n`
};
};
CDKのコード
それではLambdaとAPI Gatewayを作るためのコードを書いていきます。
package com.myorg;
import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.apigateway.LambdaRestApi;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
public class CdkHelloStack extends Stack {
public CdkHelloStack(final Construct parent, final String id) {
this(parent, id, null);
}
public CdkHelloStack(final Construct parent, final String id, final StackProps props) {
super(parent, id, props);
final Function hello = Function.Builder.create(this, "HelloHandler")
.runtime(Runtime.NODEJS_14_X)
.code(Code.fromAsset("lambda"))
.handler("hello.handler")
.build();
LambdaRestApi.Builder.create(this, "Endpoint")
.handler(hello)
.build();
}
}
もともとCdkHelloStack(final Construct parent, final String id, final StackProps props)
メソッドにはキューを作成するコードがありましたが、今回は利用しないので削除し、代わりにFunctionとLambdaRestApiをインスタンス化するコードを記載しました。
なんとこれだけでOKです。
あとはデプロイするだけになりますが、このままだとテストコードでエラーが出てしまうので修正しておきます。
@Test
public void testStack() throws IOException {
App app = new App();
CdkHelloStack stack = new CdkHelloStack(app, "test");
JsonNode actual = JSON.valueToTree(app.synth().getStackArtifact(stack.getArtifactId()).getTemplate());
assertThat(actual.toString())
.contains("AWS::Lambda::Function")
.contains("AWS::ApiGateway::RestApi");
}
diffの取得
$ mvn package
$ cdk diff
これで実際の環境と今回修正した内容の差分が見れます。
以下はdiff出力の抜粋になります。
Resources
[+] AWS::IAM::Role HelloHandler/ServiceRole HelloHandlerServiceRole
[+] AWS::Lambda::Function HelloHandler HelloHandler
[+] AWS::ApiGateway::RestApi Endpoint Endpoint
[+] AWS::IAM::Role Endpoint/CloudWatchRole EndpointCloudWatchRole
[+] AWS::ApiGateway::Account Endpoint/Account EndpointAccount
[+] AWS::ApiGateway::Deployment Endpoint/Deployment EndpointDeploymentXXXXXXX
[+] AWS::ApiGateway::Stage Endpoint/DeploymentStage.prod EndpointDeploymentStageprod
[+] AWS::ApiGateway::Resource Endpoint/Default/{proxy+} Endpointproxy
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.CdkHelloStackEndpoint115409AD.ANY..{proxy+} EndpointproxyANYApiPermissionCdkHelloStackEndpointANYproxy
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.Test.CdkHelloStackEndpoint.ANY..{proxy+} EndpointproxyANYApiPermissionTestCdkHelloStackEndpointANYproxy
[+] AWS::ApiGateway::Method Endpoint/Default/{proxy+}/ANY EndpointproxyANY
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.CdkHelloStackEndpoint.ANY.. EndpointANYApiPermissionCdkHelloStackEndpointANY
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.Test.CdkHelloStackEndpoint.ANY.. EndpointANYApiPermissionTestCdkHelloStackEndpoint
[+] AWS::ApiGateway::Method Endpoint/Default/ANY EndpointANY
deploy
あとはデプロイです。
$ cdk deploy
Do you wish to deploy these changes (y/n)? y
CdkHelloStack.Endpoint8024A810 = https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/
返却されたURLに対してアクセスしてみます。
$ curl https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/
Hello, CDK! You've hit /
後片付け
作成したリソースを削除する場合はcdk destroy
を実行します。
$ cdk destroy
Are you sure you want to delete: CdkHelloStack (y/n)? y
✅ CdkHelloStack: destroyed
参考URL
AWS Cloud Development Kit(CDK) -> Getting started with the AWS CDK
AWS CDK Intro Workshop > Java Workshop > New Project
AWS CDK Intro Workshop > Java Workshop > Hello, CDK!
Discussion