Deploy a Java Lambda Function and API Gateway with AWS CDK
Photo by Aurélien Grimpard / Unsplash
With AWS, Lambda provides server computation with no infrastructure hassle. It also provides the runtime for many programming languages like JavaScript, PHP, Golang, Java, etc...
Today, we will see how to create a Lambda function with the Java Runtime, Add an API Gateway in front to invoke the function through an endpoint.
Prerequisites
To continue this tutorial, make sure you have the following tools installed on your computer:
- An AWS account to deploy our Lambda function
- AWS CLI configured (check out this link to see how to do it)
- JDK 11 (Amazon Corretto is recommended) and Maven 3.5 or higher
- AWS CDK installed locally:
npm install -g cdk
- Docker to test the Lambda locally using AWS SAM CLI, but it is optional since you can just deploy on AWS to test
What we will build
We want to build an app that exposes an endpoint where the user can send his Height and weight; the function will calculate the Body Mass Index (BMI) and return the result. The endpoint will accept POST requests.
Create the project with the CDK
We will use the AWS CDK CLI to create a Java project, but before, let's see how to structure the project folder:
- The first folder will contain the infrastructure code like creating the Lambda function, the API Gateway, etc... We will call it
infra
. - The second folder will contain a Maven project that holds the business logic of the Lambda function. We will call it
bmi-calculator
.
Let's create the root directory and enter inside; you can give the name you want.
mkdir lambda-java-cdk
cd lambda-java-cdk
Create the infra folder
mkdir infra
cd infra
cdk init sample-app --language java
Create the function folder
This folder will host a Java project with Maven; run the command below to create a project using the CLI:
mvn archetype:generate \
-DgroupId=com.tericcabrel \
-DartifactId=bmi-calculator \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
cd bmi-calculator
Open the pom.xml file and replace the content with the code below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tericcabrel</groupId>
<artifactId>bmi-calculator</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>bmi-calculator</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<finalName>bmicalculator</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.tericcabrel.App</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
To learn more about what this update is necessary, I wrote a post that explains why.
Close the pom.xml, then run the command below to update the dependencies:
mvn dependency:resolve
Update the test file located at src/test/java/com/tericcabrel/AppTest.java
with the content below; otherwise, the project packaging will fail:
package com.tericcabrel;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
@Test
public void testApp()
{
System.out.println("Hello world from test!");
assertTrue( true );
}
}
Here is what the project directory looks like:
Install the Lambda package for Java
The bmi-calculator is just a classic Java project, but to make it behave as a Lambda Function, we need to install the Java package for AWS Lambda. Let's update the pom.xml to add the dependency:
Here are the links to the Maven repository:
Update the Maven dependencies: mvn dependency:resolve
Write the Lambda function logic
We will need a library to parse the request body from a string to an object; we will use GSON. We will also need Log4j for logging. Update the pom.xml to add these dependencies:
Update the Maven dependencies: mvn dependency:resolve
Let's create a file called RequestInput.java that will contain the request body:
Open the file App.java and replace the content with the code below:
Define the Lambda Function
The business logic for the BMI calculator is ready; now, let's define the Lambda function using the CDK. Go to the infra folder and open the file src/main/java/com/myorg/InfraStack.java
and update the code below:
The code above is responsible for bundling the Java source code and defining the Lambda function resource.
This is the step of the Bundling:
- Create a Docker container from the image of Java 11.
- Mount the Maven dependencies folder
~/.m2
of the computer inside the Docker container at the path/root/.m2
- Inside the container, the project is mounted inside the folder
asset-input
; we enter intobmi-calculator
, package the Java project and copy the .jar in the folderasset-output
. The files under/asset-output
will be zipped and uploaded to Amazon S3 as the asset by default.
For the part defining the Lambda, there are two interesting to see:
- To indicate the path where the Lambda will find the code to execute, we write:
Code.fromAsset("../", AssetOptions.builder()
Why do we do "../"? It is because the base directory is the folder infra
, so to find the code inside the bmi-calculator
folder, we must go back from one folder.
- The value of the property
handler
iscom.tericcabrel.App
; this refers to the file App.java inside the foldersrc/main/java/com/tericcabrel
.
The other settings are the basic ones like the function name, memory size, runtime version, time out, etc...
Define the API Gateway
Version 2 of the AWS API gateway is not present in the CDK library, but in a separate package because it is still unstable at the moment I'm writing this post. We will add two Maven packages. Update the pom.xml
Run mvn dependency:resolve
to install the packages
Now, update the file src/main/java/com/myorg/InfraStack.java
with the content below:
Here, we create an endpoint '/calculate' that will invoke the Lambda function. In the end, we use CfnOutput to print the URL of the API Gateway in the console.
Sending a request to <gateway-url>/calculate in the POST method will invoke the Lambda function and return the result.
Deploy the Lambda function to AWS
With the CDK, once you define the resources of your stack, you need to generate the CloudFormation template. The command to execute this step is:
cdk synth
This command will do two things:
- Build the project
bmi-calculator
to generate the JAR file - Generate the CloudFormation template from the project
infra
Once done, initialize the CloudFormation stack necessary to deploy the resources on AWS:
cdk bootstrap
Note: you only need to run this command once; this stack will be reused for your next project.
Finally, deploy on AWS and wait for the execution to complete
cdk deploy
You will get an output similar to this one:
Log into your AWS console and browse your Lambda functions; you will see two new functions, the BMI calculator function and the Lambda created to handle logs retention.
Test the Lambda function from the API Gateway
Take an HTTP client of your choice to test; I will use Postman.
Delete everything
Deleting all the resources and stack created for this application is straightforward; run the following command:
cdk destroy
Wrap up
You can now build your Serverless backend web application using Java. Here are some resources to learn more about the AWS API Gateway:
- https://docs.aws.amazon.com/cdk/api/v2/docs/aws-apigatewayv2-alpha-readme.html
- https://docs.aws.amazon.com/cdk/api/v2/docs/aws-apigatewayv2-integrations-alpha-readme.html
- https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigatewayv2-readme.html
- https://docs.aws.amazon.com/cdk/api/v2/docs/aws-apigatewayv2-authorizers-alpha-readme.html
You can find the code source on the GitHub repository.
Follow me on Twitter or subscribe to my newsletter to not miss the upcoming posts and the tips and tricks I share every week.
Happy to see you soon ?