DEV Community

Rui Teixeira
Rui Teixeira

Posted on • Edited on

AWS Lambda + Kotlin

Run AWS Lambda with Kotlin

Lambda is a buzz word nowadays, for good reasons: simple, fast and pay as you go.
Majority of lambda functions examples are written in TypeScript and, for the JVM side, Java only. That's why I'm creating this example, to anyone interested in running a Kotlin function on AWS.
I'll be using the AWS CLI only, not the AWS online console.

Create the kotlin project – gradle

First of all we need to create our kotlin project. We'll use Gradle to do it, but translate it to Maven should be trivial.
Create a folder wherever you want, navigate to it in the command shell and execute the following:

gradle init

After that, select the following options:

  • Select type of project to generate: library
  • Select implementation language: Kotlin
  • Select build script DSL: Groovy
  • Generate build using new APIs and behavior (some features may change in the next minor release): no

Dependencies

To run our function on AWS we need to add some dependencies to our project.

implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'

Apart from AWS specific, we'll need a fat jar, so we need to add a plugin to generate it:

id "com.github.johnrengelman.shadow" version "7.1.2"

That's all we need to have our proof of concept.

Create the actual Kotlin function

I'm using IntelliJ IDE

Our Lambda function will be very simple:
Implement an echo function, i.e., it will return the received input.

Let's create our main Class. I'll create the package com.ruimptech.echo inside src/main/kotlin. Inside that package I'll create the main kotlin class, named App.

Project structure

In order to run in AWS, our main class needs to implement the RequestHandler interface.

Implementing RequestHandler interface

As you can see in the image, there's an error, that's because the RequestHandler interface requires to specify the input and output data type. To fix that, we'll create a class for input and another for output and use them to fix the interface error.

Input class

package com.ruimptech.echo

class EchoIn {
    var content: String = ""
}
Enter fullscreen mode Exit fullscreen mode

Receives a simple content String.
Example: { "content": "hello" }

Output class

package com.ruimptech.echo

data class EchoOut(val content: String)
Enter fullscreen mode Exit fullscreen mode

Very similar to the input class, contains the output content String, that in our proof of concept will be the received input.

Note that our EchoIn class is not a data class, that's because a data class will not work on AWS. If we use a data class as the input, lambda execution will terminate immediately due to a initialization error.

Now that we have input and output classes, we can fix our lambda function (App class).

package com.ruimptech.echo

import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.LambdaLogger
import com.amazonaws.services.lambda.runtime.RequestHandler

class App : RequestHandler<EchoIn, EchoOut> {
    override fun handleRequest(input: EchoIn, context: Context): EchoOut {
        val logger: LambdaLogger = context.logger
        logger.log("ECHO INPUT RECEIVED: " + input.content)
        return EchoOut("Echo: ${input.content}")
    }
}
Enter fullscreen mode Exit fullscreen mode

At this point, the function is ready! Let's go over what is going on:

  1. RequestHandler<EchoIn, EchoOut>
    • We say to our lambda function that EchoIn and EchoOut are the input and output data types.
  2. override fun handleRequest
    • The actual code to be run on each incoming request
    • As mentioned before, the function is very simple. We print a log with the received input and return it inside a EchoOut instance.

Create a fat jar

The com.github.johnrengelman.shadow plugin allow us to create a fat jar with a simple command:
./gradlew shadowJar
As a result, we'll find a file named lib-all.jar inside the build/libs directory, that's our fat jar.

Deploy the lambda function

We have everything in place in our computer, now let's send it to AWS.
As any AWS deploy, we need a template to specify what we want to do. We'll use an existing AWS template (you can find the original version here) and tweak some properties:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Kotlin Lambda Function
Resources:
  function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/lib-all.jar
      Handler: com.ruimptech.echo.App::handleRequest
      Description: Kotlin function
      Runtime: java11
      MemorySize: 512
      Timeout: 10
      # Function's execution role
      Policies:
        - AWSLambdaBasicExecutionRole
        - AWSLambda_ReadOnlyAccess
        - AWSXrayWriteOnlyAccess
        - AWSLambdaVPCAccessExecutionRole
      Tracing: Active
Enter fullscreen mode Exit fullscreen mode

The main changed parameters are:

  • CodeUri
    • Where is the fat jar to send to AWS
  • Handler
    • What is the function to run
  • Description

Save this template in a file named template.yml, place it in the lib folder of the project:

Lambda template file location

From that point on, I assume you have an AWS account and the CLI is correctly configured in your computer. If not, please check this out

Now, to deploy the function we need 3 steps:

  1. Create a S3 bucket where the final template will be stored (the template.yml file we just created is a template to generate the final template, don't worry too much about it)
  2. Generate the final template and save it on the bucket created before
  3. Deploy the final template

These 3 steps are directly converted to 3 CLI commands:

  1. aws s3 mb s3://lambda-kotlin
  2. aws cloudformation package –template-file template.yml –s3-bucket lambda-kotlin –output-template-file template-out.yml
    • Based on our template.yml, the CLI will generate the final template - template-out.yml - that we can use in the final step
  3. aws cloudformation deploy –template-file template-out.yml –stack-name lambda-kotlin –capabilities CAPABILITY_NAMED_IAM
    • Use the final template to deploy the lambda function

That' it! Our Kotlin Lambda function is on AWS!

Testing

Now that we have our lambda online, we can test it. To do it we need to know the name of our function. The simplest way to find it is going into AWS console and copy the name:

Finding lambda function name

Now that we have our function name, let's call it from the CLI.

In order to run our test, we need to enable the literal input, that means we'll pass the payload from the command line. To enable it, open the CLI config file:
MacOS and Linux: ~/.aws/config
Windows: %USERPROFILE%\.aws\config
Add the line:
cli_binary_format = raw-in-base64-out
If you want more information, check it here

The payload needs to match our EchoIn class, so to test the lambda we need to run something like:

aws lambda invoke \
  --function-name lambda-kotlin-function-R4M2Bf9fxxBf \
  --payload '{ "content": "Hey!" }' \
  out.json
Enter fullscreen mode Exit fullscreen mode

The content of the response will be stored in out.json file and the content will be:

{"content":"Echo: Hey!"}

That's it, you just deployed and run a Kotlin Lambda function on AWS!

You can find the code on GitHub.

Top comments (0)