In this lab we will:
hello-world
functionYou completed this lab if you:
hello-world
functioncurl
)First we want to create a new serverless project with Java. Then we want to convert it to use Gradle instead of Maven.
# Create a new folder for your project:
mkdir serverless-workshop
# Change to the newly created directory
cd serverless-workshop
# Now bootstrap it
cdk init app --language java
If everything works as intended you should see output similar to this:
Applying project template app for java
# Welcome to your CDK Java project!
This is a blank project for Java development with CDK.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
It is a [Maven](https://maven.apache.org/) based project, so you can open this project with any Maven compatible Java IDE to build and run tests.
## Useful commands
* `mvn package` compile and run tests
* `cdk ls` list all stacks in the app
* `cdk synth` emits the synthesized CloudFormation template
* `cdk deploy` deploy this stack to your default AWS account/region
* `cdk diff` compare deployed stack with current state
* `cdk docs` open CDK documentation
Enjoy!
Initializing a new git repository...
Executing 'mvn package'
✅ All done!
We want to use Gradle instead of Maven, so do the following:
# convert project to gradle
gradle init
It should print something like:
Found a Maven build. Generate a Gradle build from this? (default: yes) [yes, no] yes
> Task :init
Maven to Gradle conversion is an incubating feature.
Get more help with your project: https://docs.gradle.org/6.5.1/userguide/migrating_from_maven.html
BUILD SUCCESSFUL in 4s
2 actionable tasks: 2 executed
Open the file cdk.json
and change it to:
{
"app": "./gradlew build run",
"context": {
"@aws-cdk/core:enableStackNameDuplicates": "true",
"aws-cdk:enableDiffNoFail": "true"
}
}
At the top of your build.gradle
file, add the application plugin and set the main class. Also fix the Maven repo URL. It should look like this:
plugins {
id 'application'
id 'java'
id 'maven-publish'
}
application {
mainClassName = 'com.myorg.ServerlessWorkshopApp'
}
repositories {
mavenLocal()
maven {
url = uri('https://repo.maven.apache.org/maven2')
}
}
Now delete the pom.xml
file, you won’t need it anymore.
Now we will create our first Lambda function. We need to set up the Gradle structure, implement the handler, and wire it up with the CDK.
Create a Gradle project in a folder called lambda
:
# Create a folder to hold the code for the Lambda function
mkdir lambda
cd lambda
# Bootstrap
gradle init --type java-library --dsl groovy --test-framework junit-jupiter --project-name lambda --package com.myorg
We need some dependencies, paste these into dependencies
section in the build.gradle
file:
implementation 'com.amazonaws:aws-lambda-java-core:1.2.1'
implementation 'com.amazonaws:aws-lambda-java-events:2.2.9'
runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.2.0'
AWS Lambda expects a deployment package which is a ZIP file with the Java classes plus libraries, so paste this at
the bottom of build.gradle
:
task buildZip(type: Zip) {
from compileJava
from processResources
into('lib') {
from configurations.runtimeClasspath
}
}
build.dependsOn buildZip
Also set the source compatibility to be 1.8
:
sourceCompatibility = '1.8'
Create a class called HelloWorldHandler
.
Paste in the following:
package com.myorg;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
public class HelloWorldHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
response.setStatusCode(200);
response.setBody("Hello World!");
return response;
}
}
Try to compile it, it should work.
For bonus points implement a unit test for the class above. Skip this if you are in a rush.
We’ll need to configure our project and write some more code
Navigate back to the top level project, and open settings.gradle
.
Paste the following:
include 'lambda'
Now open build.gradle
and add these dependencies:
implementation 'software.amazon.awscdk:core:1.57.0' // Version must match with the version of aws-cdk
implementation 'software.amazon.awscdk:lambda:1.57.0'
implementation 'software.amazon.awscdk:apigatewayv2:1.57.0'
implementation project(':lambda') // Depend on our subproject, so it will always be rebuilt
Open the file ServerlessWorkshopStack.java
and paste the following:
package com.myorg;
import software.amazon.awscdk.core.CfnOutput;
import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Duration;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.apigatewayv2.AddRoutesOptions;
import software.amazon.awscdk.services.apigatewayv2.HttpMethod;
import software.amazon.awscdk.services.apigatewayv2.LambdaProxyIntegration;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.apigatewayv2.HttpApi;
import java.util.Arrays;
public class ServerlessWorkshopStack extends Stack {
public ServerlessWorkshopStack(final Construct scope, final String id) {
this(scope, id, null);
}
public ServerlessWorkshopStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Create the Lambda function
Function myFunc = Function.Builder.create(this, "helloWorld")
.code(Code.fromAsset(System.getProperty("user.dir") + "/lambda/build/distributions/lambda.zip"))
.handler("com.myorg.HelloWorldHandler")
.runtime(Runtime.JAVA_8)
.memorySize(512) // Java loves memory
.timeout(Duration.seconds(10)) // Class loading can take some time
.build();
// Wire up the Lambda function to be accessible at path '/hello-world'
LambdaProxyIntegration lambdaProxyIntegration = LambdaProxyIntegration.Builder.create().handler(myFunc).build();
HttpApi httpApi = HttpApi.Builder.create(this,"HttpApi").build();
httpApi.addRoutes(AddRoutesOptions.builder()
.path("/hello-world")
.methods(Arrays.asList(HttpMethod.GET))
.integration(lambdaProxyIntegration)
.build()
);
// Output the URL for later consumption
CfnOutput.Builder.create(this, "URL").value(httpApi.getUrl() + "hello-world").build();
}
}
Open the file ServerlessWorkshopApp.java
and change the string literal in the following line to something unique:
new ServerlessWorkshopStack(app, "ServerlessWorkshopStackUniqueSuffix");
This will ensure that you don’t interfere with the other workshop participants.
For the sake of our tutorial remove the test class:
rm src/test/java/com/myorg/ServerlessWorkTest.java
Maybe we will fix this later.
Open your shell, make sure you have your AWS credentials configured. Now run:
cdk synth
cdk deploy
Now use the output from above and call your HTTP handler, it should print “Hello world!”.
If you check out the CloudFormation console you will notice a new stack with the name you just defined in the guided deployment. CloudFormation is essentially a tool to provision, maintain and remove infrastructure in AWS. AWS CDK uses CloudFormation under the hood to deploy the infrastrucutre we describe in this workshop.
Try to figure out:
Try to log something and find the output in Cloudwatch Logs.