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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Write an AWS Lambda Function with Kotlin and Micronaut
20 mins
- Prerequisites
- Writing the Function
- Create a Kotlin App with Gradle
- Code a Pirate Translator
- Test the Pirate Translator
- Create an AWS Lambda RequestHandler
- Gradle Shadow Plugin
- Deploying to AWS Lambda
- Create a Function
- Test Your Function
- Add an API-Gateway Trigger
- Writing the Function with Micronaut
- Where to Go From Here?
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:
- Basic knowledge of Kotlin. If you are new to Kotlin, check out our Kotlin tutorials or the book Kotlin Apprentice.
- An Amazon Web Services (AWS) account.
- JDK 8 installed in your computer.
-
Gradle 5.6.2 or greater. The easiest way to install Gradle in your computer is to use SDKMan.io. Once you install SDKMan you can open a Terminal and run
sdk install gradle
. You can also use Homebrew and the commandbrew install gradle
.
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:
- You create a
Map
with some pirate translations. - 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:
- Annotate the method with
@Test
. - Instantiate the class under test.
- 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.
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.
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:
- Create a
RequestHandler
. Lambda stream request handlers implement AWS Lambda Function application logic using input and output streams. - Instantiate a
PirateTranslator
. - Override
handleRequest
which takes aHandlerInput
and responds with aHandlerOutput
. - Use the translator to populate
pirateMessage
, the second argument of theHandlerOutput
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.