Using Kotlin in a Serverless Architecture with AWS Lambda — Part 1: Setting Up the Project

Quick example of how to use Kotlin using Serverless Framework and AWS Lambda

Welcome to the first in a series of articles about Using Kotlin in a Serverless Architecture with AWS Lambda. In these articles I will introduce a set of tools, concepts and code examples that will help you in the process of creating beautiful, serverless-based products.

Index

The Journey

A couple of months ago, my wife and I decided to start a non-profit project seeking to reduce the abandonment rate of pets. The project is called PetPets and it connects people who want to give up a pet for adoption with those who want to receive them. In any case, given that the project was a non-profit initiative and the money to support the platform would come from our pockets, we needed to have a scalable, on-demand and cheap solution that we could afford.

For the frontend, we decided to go with a React project deployed on AWS S3. The FLUX Architecture, community, support, component based design and profesional experience with it, made React a perfect solution. Regarding S3, the service level agreemeent in terms of durabilty and availability, as well as a monthly price of $5 USD per month at most (for our particular case), made it a really good solution (we also use Cloudfront for improving caching and HTTPS support).

However, what about the backend? We needed an API-based solution ready to work with React, flexible enough for new requirements and, again, not too expensive. In the past, I’ve used AWS Lambda to develop highly scalable and available Microservices. Even with its limitations, I thought that it was a nice way to keep our architecture as serverless as possible. In previous projects, a combination of NodeJS + AWS Lambda was the solution, but I didn’t like the maintainability, debugging and performance of that too much. I’m not saying that it is bad, but I wanted something easier, faster and almost out of the box.

That’s how my journey of finding the best language and framework for this project started.

Every Millisecond Counts

In AWS, every 0.1 second has a cost! We could not afford to spend thousands (not even hundreds) of dollars in a non-profit project, specially because we don’t have any funding or donations. At that moment, I started checking what could be a good solution in terms of performance and maintainability.

During my research I found a really good article from Yan Cui called “Comparing AWS Lambda Performance When Using NodeJS, Java, C# or Python”. In this article the author makes four observations:

C# is the slowest language

Java is the fastest and most consistent one

Static languages have more consistent performance

Java packages are big

For me, it was amazing to see that Java was 6 times faster than C# and 3 times faster than NodeJS. Also, Java’s performance was really consistent, while Python and NodeJS had quite a random behaviour.

Update: Yun Zhi Lin created a new report based on Cui’s post. In this new article the results were a little bit different:

.Net Core 2.0 is now the one with the best performance

Go and Java have a similar performance

Compiled and dynamic languages have a consistent performance

Go packages are bigger than Java

Based on both articles, the final conclusions are:

.Net Core 2.0 is bringing a first class citizen performance to languages like C# and F#

Java still has a good performance

As Cui’s states about AWS Lambda: “Architects and engineers should have more confidence in choosing from all the available runtimes”

Kotlin vs Java

Based on the previous articles, Java became a good solution. However… Java? Well, I’ve always consider Java as my “native language”, but I wanted something easy to code and maintain. That’s why I decided to use a different language on the JVM.

For a long time, I was quite excited about the idea of testing Kotlin in a real product, so I though that maybe this was the moment to do it. But why Kotlin over Java? There are several reasons but here it comes a couple of them:

Kotlin provide a more concise, productive and safer alternative to Java Kotlin is interoperable with Java and runs with the same performance Kotlin is a functional and Object Oriented programming language Kotlin is becoming a trend. An example of that is Android, where people are starting to using Kotlin instead of Java.

In conclusion, it looks like Kotlin has more benefits over Java, than the other way around. So that’s when this trip started.

Serverless Framework

In the past, I’ve used ClaudiaJS as my AWS Lambda framework. ClaudiaJS is an excellent framework: reduces your boillerplate code, manages deployment environments, has easy and simple deploy commands and version management for your API. But what was the issue? Well, ClaudiaJS is just for NodeJS + AWS Lambda projects.

Then I found Serverless Framework, an agnostic and almost out of the box solution for AWS, Google Code, Microsoft Azure and IBM Open Whisk. Serverless came with templates for multiple languages, including Kotlin, and is becoming the de facto framework for any serverless project. AWS also has an alternative called SAM, however I loved the agnostic and plug-and-play concept from Serverless Framework.

So let’s stop talking and let’s begin with some code.

Creating the project

The first step is to install Serverless framework. To do that, install nodeJS and then run the next command:

npm install -g serverless

Now let’s create our first project. I’m going to use the kotlin-jvm-gradle template, but if you want to use different one (maybe you prefer Maven) you can always choose a another option.

serverless create --template aws-kotlin-jvm-gradle --path your_service

By default, Serverless can also help you creating your AWS credentials file, you just need to execute this command:

serverless config credentials --provider aws --key EXAMPLE --secret EXAMPLEKEY

After using those commands, you should have a default folder structure like this:

Default folder structure using the kotlin-jvm-gradle template

To test that everything is working, from your project’s root directory, run the next command (then go to your AWS Account and use the UI console to test!):

./gradlew deploy

Note: According to Serverless documentation you can use the command serverless deploy -v . However, with Java-based-projects that’s not true because it needs to create a Fatjar with all the needed requirements (so the command will fail). By default, Serverless will set shadow as a dependency in the gradle file for those purposes. The deploy command will generate a build file called <project_name>-all.jar that is the one that’s going to be uploaded to the AWS Lambda function.

Setting up the project

Let’s try to understand a little bit the autogenerated project structure. First of all we have a serverless.yml file. This file will define the basic configuration of our project, as well as the resources, functions, endpoints and events that we are going to handle. Let’s check a couple of those properties:

Service: Name of the project itself. For Serverless framework it can be considered as a container of functions. In later articles, I will explain some SOA concepts that will help us to define the correct granularity of our functions.

service: your-service

Provider: The cloud provider that we are going to use and the runtime environment. In this particular case we are going to use AWS and Java8

provider:

name: aws

runtime: java8

There is a couple of commented values that you may want to uncomment, like environment, stage, region and memory size. This last one is really important, because with Java a small memory size could generate erratic/non-consistent behaviour. My advise is to have at least 1GB of memory, so you can have something like:

provider:

name: aws

runtime: java8



# You can overwrite defaults here

stage: dev # Use dev, stag, prod, etc

region: eu-west-1 # Your preference region, in my case Ireland

memorySize: 1472 # It has worked for me

The last two properties that serverless also provides are environment (where you can define lambda environment variables) and IAM Role Statements. The first property is good if you’re not going to persist critical data. In case of credentials management, it is always better to use a Parameter Store, a vault (like Terraform Vault) or IAM roles (using statements).

Package: It just defines the packaging information (name and build directory).

package:

artifact: build/libs/your-project-dev-all.jar

Functions: This is the place where you’re going to define your functions and events that would trigger them. The minimum data required for your function is the name and handler file for it. By default you will see something like this:

functions:

hello:

handler: com.serverless.Handler

A cool thing about serverless is that in this definition we can add our HTTP events, indicating that we want an API Gateway with that specific endpoint. Something like this:

functions:

hello:

handler: com.serverless.Handler

events:

- http:

path: hello

method: get

In the previous example, serverless will build an API Gateway with an endpoint /hello that will accept HTTP GET requests that call the main function in the Handler.kt file.

https://<lambda_id>.execute-api.<region>.amazonaws.com/<stage>/hello

Another nice feature is that we can define what other events from SNS, S3, Cloudwatch, Alexa, Stream and Cognito can trigger the function. In the next case, the function will be triggered every single 10 minutes or via an API Gateway request.

functions:

hello:

handler: com.serverless.Handler

events:

- http:

path: hello

method: get

- schedule: rate(10 minutes)

Resources: This section is one of the big helpers from Serverless, given that we can keep control over the infrastructure that supports our code. Do you need DynamoDB tables, S3 Buckets, or Cognito pools? Just put it here and that’s all. This feature give us the opportunity to have everything in the same place and to manage the whole life cycle of our app using this serverless.yml file. If at any moment you remove an element from here, serverless state will understand that you no longer need that resource and will delete it (so be careful with that).

The next example defines a DynamoDB for our Users with an email column and Hash key (as well other properties like the read and write capacity units).

resources:

Resources:

UsersDynamoDbTable:

Type: 'AWS::DynamoDB::Table'

DeletionPolicy: Retain

Properties:

AttributeDefinitions:

-

AttributeName: email

AttributeType: S

KeySchema:

-

AttributeName: email

KeyType: HASH

ProvisionedThroughput:

ReadCapacityUnits: 1

WriteCapacityUnits: 1

TableName: Users

Note: If you want to know more about the serverless.yml file, please go to their website.

Final Thoughts

In this article we created a new Kotlin serverless project for AWS Lambda. I hope you have a better idea of the benefits of the framework and the features that it provides to us. In the next articles I’m going to present in depth some other concepts, tools and code that will make our serverless Kotlin projects shine. See you soon and don’t forget to clap & subscribe.

Part 2: Setting up your local development environment