You Don’t Need frameworks for a Serverless API in Java

Let’s get it straight. Serverless is ultra simple: you just focus on your code, and a cloud provider handles all the maintenance and scaling. No one actually needs training, special support, writing/reading books, and especially using dedicated frameworks in order to start using serverless architecture.

You’re locking yourself to a framework with its own conventions, configurations with special syntax, etc., in turn, it promises a set of features, that you actually don’t need, almost no one needs. My favorite feature is being a “cloud-agnostic”. I’ve heard similar things in the Java world about JPA for years. Do you know how many times I’ve switched to other JPA implementation? None.How many people do I know who actually have done this? Zero. How many even considered switching? Nil. Nada. Zilch. Because this is a marketing feature, no one actually needs it. Also, it’s a lie.

Seriously, if someone says “this is a blah-blah-agnostic thing, you can swap the underneath blah-blah to some other blah-blah anytime”, don’t trust the person. He is either a junior/middle developer or sells support for the “blah-blah-agnostic thing”. Nothing is actually completely agnostic, in real apps, there are always some specifics, it sucks, but it’s true.

Thus, I came up with my cloud-agnostic framework… Just kidding.

In case you want to run your java web application on AWS Lambda, you may use this super simple micro-library.

If you missed the introduction into the serverless java servlets, you may want to check out this article.

The Way I‘d Implement a Serverless RESTful API in Java

To be honest, I wasn’t sure if it’s worth mentioning JAX-RS separately, because all JAX-RS implementations have support for servlets, and we already know how to serve servlets via AWS Lambda. Then, I remembered a set of emails where I got asked to help with the library in their projects: people do need a quick and easy step-by-step instruction in order to be able to try out something, even though this library is literally tiny.

Preparing Your JAX-RS API

Suppose, we have the following JAX-RS resource that we want to expose via AWS Lambda:

import javax.ws.rs.*;
@Path("ping")
public class PingResource {
@GET
public String get() {
return "OK";
}
}

This resource has just one method implemented returning “OK” string. Now, in order to use our micro-library, you will have to add my bintray repository to your pom.xml, it’s identical to what we had in the servlets example (here I assume you’re using Maven):

<repository>
<id>bintray</id>
<url>http://dl.bintray.com/bleshik/maven</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>

Then add the dependency:

<dependency>
<groupId>com.github.bleshik</groupId>
<artifactId>aws-lambda-servlet</artifactId>
<version>1.0</version>
</dependency>

One more thing — you have to build a fat jar in order to deploy your code to AWS Lambda. In Maven you’ll need to add this:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

The final step before we are able to deploy, we need to create an AWS Lambda handler that serves our JAX-RS API. Here is the most simple option:

import util.JerseyRequestHandler;
public class JerseyAdapter extends JerseyRequestHandler {
public JerseyAdapter() {
super("/", PingResource.class);
}
}

In the example, I’ve used a shortcut constructor that simply accepts the resource classes. Alternatively (and more useful in real life), you may pass ResourceConfig, like:

import util.JerseyRequestHandler;
import org.glassfish.jersey.server.ResourceConfig;
public class JerseyAdapter extends JerseyRequestHandler {
public JerseyAdapter() {
super("/", new ResourceConfig(PingResource.class));
}
}

BOOM! You’re ready to deploy your jar to AWS Lambda.

It’s worth mentioning that the library does not use any HTTP servers underneath (whereas, for example, aws-serverless-express does start express), which is nice for the bootstrap time.

Deploying the Jar to AWS Lambda

As we’ve done with the servlet, we need to use the whole bunch of AWS services in order to actually have the API exposed: S3, Lambda and API Gateway. To make things easier, you may launch the API via CloudFormation using the link below:

https://console.aws.amazon.com/cloudformation/home?#/stacks/new?templateURL=https://s3-eu-west-1.amazonaws.com/bleshik/aws-lambda-servlet-example-jersey-CloudFormation.json

After the template is executed successfully, find your API in the API Gateway dashboard, then go to Stages and find the “api” stage, click and you will see the URL of your API. You can try out our “/ping” resource:

https://waaoyueyv9.execute-api.eu-west-1.amazonaws.com/api/ping

The Example Sources

The complete source code for this particular example can be found here.
You can download the CloudFormation template and correct it for your needs.

What’s Next?

First of all, you might already know that the first request to your AWS Lambda is slower than the subsequent ones. This is due to the fact that AWS Lambda is loaded into the memory and initialized on the first request only, it is called a “cold start”. In order to workaround it, you may want to warm it up, which is not as straightforward as may think. You may want to check out the article on this particular topic.

Also, if you’re not into Java, you might like to learn my Top 5 struggles with NodeJS.

Subscribe to the mailing list in order to get the next article as soon as possible.

Comments, likes, and shares are highly appreciated. Cheers! ❤️