Write an AWS Lambda Function with Kotlin and Micronaut

In this Kotlin tutorial, you’ll learn how to create a “Talk like a pirate” translator and deploy it to AWS Lambda as a function. By Sergio del Amo.

4.3 (9) · 1 Review

Download materials
Save for later
Share

Serverless solutions such as AWS Lambda allow developers to run code without thinking about servers. Moreover, they offer you the ability to pay only for the compute time you consume instead of a fixed monthly rate. They are becoming especially suited for scenarios such as mobile phone application back-ends.

In this tutorial, you’ll take the following steps to create an AWS Lambda function using Kotlin:

  • Create a Kotlin project using Gradle.
  • Add a “Talk like a pirate” translator to the project.
  • Build an AWS Lambda RequestHandler.
  • Deploy your function to AWS.
  • Add an API-Gateway Trigger.
  • Re-do the project using the Micronaut framework, and re-deploy.

Prerequisites

In order to follow along with this tutorial step-by-step, you’ll need the following:

You’ll be creating the tutorial project from scratch, and you can download the final project using the Download Materials button at the top or bottom of the tutorial.

Writing the Function

Time to get started creating your AWS Lambda function with Kotlin!

Create a Kotlin App with Gradle

Open a Terminal, make a new directory named pirate-translator, cd into the new empty directory, and type gradle init. You’ll see the following output:

$ gradle init
Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 

Select application, type 2, and press return.

Then, gradle will prompt you to choose an implementation language:

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Swift

Select Kotlin, type 4, and press return.

Then, you’ll be prompted to choose a Build script DSL:

Select build script DSL:
  1: Groovy
  2: Kotlin
  Enter selection (default: Kotlin) [1..2] 2

Select Kotlin DSL, type 2, and press return.

As project name enter pirate-translator

As source package enter com.raywenderlich.

Congratulations! You have created a Kotlin app which builds using Gradle.

Code a Pirate Translator

In this section, you are going to create Kotlin classes. You can use any text editor, but I recommend you use IntelliJ IDEA 2019.2 or later (Community or Ultimate) by JetBrains – the company behind Kotlin.

If you’re using IntelliJ IDEA, click File ➤ Open and open the pirate-translator directory you made before.

Create a new Kotlin file named PirateTranslator.kt and place in the directory src/main/kotlin/com/raywenderlich. Add an interface as contract for the Talk like a pirate translator.

// src/main/kotlin/com/raywenderlich/PirateTranslator.kt
package com.raywenderlich

interface PirateTranslator {
    // 1
    fun translate(message: String): String
}

In the interface, you specify a translate() method which takes a String and returns a String.

Next you’ll write a Pirate translator brain :]

It should have the following behavior:

  • For input Yes, it returns Aye.
  • For input Hello, it returns Ahoy.
  • For input Yes, Captain!, it returns Aye Aye!.

For example, for input,

“Hello, I am Captain Jack Sparrow”

the pirate translator returns:

“Ahoy!, I am Captain Jack Sparrow”

For your implementation of PirateTranslator, create a new file named DefaultPirateTranslator.kt and place it under src/main/kotlin/com/raywenderlich. Add the class DefaultPirateTranslator:

// src/main/kotlin/com/raywenderlich/DefaultPirateTranslator.kt
package com.raywenderlich

class DefaultPirateTranslator : PirateTranslator {

    // 1
    val replacements = mapOf("Hello" to "Ahoy!", "Yes" to "Aye!", "Yes, Captain!" to "Aye Aye!")
    
    override fun translate(message: String): String {
        var result = message
        // 2
        replacements.forEach { k, v -> result =    result.replace(k, v) }
        return result
    }
}

In this code:

  1. You create a Map with some pirate translations.
  2. You replace any occurrences in the input string with pirate lingo.

Test the Pirate Translator

Next you’ll add a test for PirateTranslator. Create a file under src/test/kotlin/com/raywenderlich and name it PirateTranslatorTest.kt.

Add your test class:

//src/test/kotlin/com/raywenderlich/PirateTranslatorTest.kt
package com.raywenderlich

import kotlin.test.Test
import kotlin.test.assertEquals

class PirateTranslatorTest {
    // 1
    @Test fun testPirateTranslator() {
        // 2     
        val classUnderTest : PirateTranslator = DefaultPirateTranslator()
        
        // 3
        assertEquals("Ahoy!, I am Captain Jack Sparrow", classUnderTest.translate("Hello, I am Captain Jack Sparrow"))
        // 3
        assertEquals("Aye!", classUnderTest.translate("Yes"))
    }
}

Here you:

  1. Annotate the method with @Test.
  2. Instantiate the class under test.
  3. Create assertions to verify the expected behavior.

To run the test, in Terminal in the project root directory, run the following command:

$ ./gradlew test --tests=com.raywenderlich.PirateTranslatorTest

You should see a BUILD SUCCESSFUL message if the test passes. If the test failed, you’d see an exception. You can also run the test in IntelliJ IDEA, by pressing the green run button next to the test method.

Run the test in IntelliJ

Create an AWS Lambda RequestHandler

Your project needs to accept input, pass it to the pirate translator, and respond with the translated output. You’ll do this with an AWS Lambda RequestHandler.

Create a class named HandlerInput under src/main/kotlin/com/raywenderlich. This class will encapsulate the message you are going to input into your Talk like a pirate serverless function. Set up the class like this:

// src/main/kotlin/com/raywenderlich/HandlerInput.kt
package com.raywenderlich

class HandlerInput {
    var message: String = ""
}

Note that you are not using a Kotlin data class for the input, as that would cause issues when using it to bind JSON in the AWS Lambda RequestHandler.

Now create a Kotlin data class named HandlerOutput under src/main/kotlin/com/raywenderlich. This class will encapsulate the translation you will receive from the Talk like a pirate serverless function. The data class should look like this:

// src/main/kotlin/com/raywenderlich/HandlerOutput.kt
package com.raywenderlich

data class HandlerOutput(val message: String, val pirateMessage: String)

Now you need to add the AWS Lambda dependency. Modify the file build.gradle.kts, by adding the following dependency in the dependencies block:

implementation("com.amazonaws:aws-lambda-java-core:1.2.0")

The aws-lambda-java-core dependency is a minimal set of interface definitions for Java support in AWS Lambda.

Open the Gradle tab in IntelliJ IDEA and hit the sync button to synchronize the dependencies.

Syncing dependencies

Replace the contents of src/main/kotlin/com/raywenderlich/App.kt with the following:

//src/main/kotlin/com/raywenderlich/App.kt
package com.raywenderlich

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

// 1
class App : RequestHandler<HandlerInput, HandlerOutput> {
    // 2
    val translator : PirateTranslator =   DefaultPirateTranslator()

    // 3
    override fun handleRequest(input: HandlerInput?, context: Context?): HandlerOutput {
        input?.let {
            // 4
            return HandlerOutput(it.message, translator.translate(it.message))
        }
        return HandlerOutput("", "");
    }
}    

Here you do the following:

  1. Create a RequestHandler. Lambda stream request handlers implement AWS Lambda Function application logic using input and output streams.
  2. Instantiate a PirateTranslator.
  3. Override handleRequest which takes a HandlerInput and responds with a HandlerOutput.
  4. Use the translator to populate pirateMessage, the second argument of the HandlerOutput constructor.

Replace the contents of src/test/kotlin/com/raywenderlich/AppTest.kt with:

//src/test/kotlin/com/raywenderlich/AppTest.kt
package com.raywenderlich

import kotlin.test.Test
import kotlin.test.assertEquals

class AppTest {
    @Test fun testAppHasAGreeting() {
        val classUnderTest = App()
        val input = HandlerInput()
        input.message = "Hello"
        val expected = HandlerOutput("Hello", "Ahoy!")
        var output = classUnderTest.handleRequest(input, null)
        assertEquals(expected, output)
    }
}    

The above test verifies that given a HandlerInput with a message of value “Hello”, the response (the HandlerOutput) contains a pirateMessage with value “Ahoy!”.

Go ahead and run the test the same way as before, either from a Terminal using gradlew, or right in IntelliJ IDEA.