AWS Lambda in Kotlin using Spring Cloud Function

Upasana | August 01, 2020 | 5 min read | 455 views | AWS Tutorials


In this tutorial we will use Spring Cloud Functions (version 2.x) in Kotlin to create and deploy a simple AWS Lambda.
AWS Lambda

AWS Lambda makes it incredibly easy and cost-effective (no charge when code is not running) to run your code at arbitrary scale in the cloud. Simply write the handler code for your function and upload it to Lambda. The service takes care of hosting and scaling the function for you.

For more information:

https://aws.amazon.com/lambda/

Spring Cloud Function

Spring cloud function project has following goals:

  • Promote the implementation of business logic via functions.

  • Decouple the development lifecycle of business logic from any specific runtime target so that the same code can run as a web endpoint, a stream processor, or a task.

  • Support a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).

  • Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.

Outline of this tutorial

  1. Create Spring Cloud Function for the Number reversal program

  2. Upload Spring Cloud Function to AWS Lambda

  3. Use Java Client to invoke the Lambda Function

  4. Use Kotlin Client to invoke the Lambda Function

Create Spring Cloud Function Project

Create a new Spring Boot project using template at Spring Initializer.

start spring io scf

Problem statement

We will create a simple lambda function that takes an input number and reverses it.

Lets define the domain models: We need wrapper methods for accepting input and providing result. Jackson will handle the JSON marshalling for these objects.

NumberInput & NumberOutput
package com.shunya.reverse

class NumberInput {
    var input: Long = 0
}


class NumberOutput {
    var result: Long? = null
}

Now lets create a FunctionHandler: We need to specify this handler in AWS lambda configuration later on.

Handler.kt
package com.shunya.reverse

import org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler

class Handler : SpringBootRequestHandler<NumberInput, NumberOutput>(LambdaApp::class.java)

Now lets define the actual Function that will take care of lambda request. This class will also act like a SpringBoot Application that will start the container.

LambdaApp.kt
package com.shunya.reverse

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import java.util.function.Function

@SpringBootApplication
class LambdaApp {

    @Bean
    fun function(mathService: MathService, objectMapper: ObjectMapper): Function<NumberInput, NumberOutput?> {
        return Function {
            val output = NumberOutput()
            output.result = mathService.reverse(it.input)
            return@Function output
        }
    }

    companion object {

        @JvmStatic
        fun main(args: Array<String>) {
            SpringApplication.run(LambdaApp::class.java, *args)
        }
    }
}

The actual service that calculates the reverse of a number is defined following:

MathService.kt
package com.shunya.reverse

import org.springframework.stereotype.Service

@Service
class MathService {

    fun reverse(num: Long): Long {
        var num = num
        var sum: Long = 0
        while (num != 0L) {
            val lastDigit = num % 10
            sum = sum * 10 + lastDigit
            num /= 10
        }
        return sum
    }
}

Now we are almost ready with our simple Spring Cloud Function that we can deploy to AWS Lambda.

Creating the build artifact

We are using aws specific dependencies (spring-cloud-function-adapter-aws) in our project, which creates aws specific artifacts during the build:

build.gradle
dependencies {
    compile 'com.amazonaws:aws-lambda-java-core:1.2.0'
    compile 'com.amazonaws:aws-lambda-java-events:2.2.6'
    compile 'com.amazonaws:aws-java-sdk-s3:1.11.557'

    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    compile "org.jetbrains.kotlin:kotlin-reflect"

//    compile 'org.springframework.cloud:spring-cloud-starter-function-web:2.1.0.RELEASE'
    compile 'org.springframework.cloud:spring-cloud-function-adapter-aws:2.1.0.RELEASE'

    testCompile 'org.springframework.boot:spring-boot-starter-test'
    testCompile 'net.bytebuddy:byte-buddy:1.6.4'
    testCompile 'org.objenesis:objenesis:1.2'
    testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
    testCompile 'org.spockframework:spock-spring:1.1-groovy-2.4'
}

Run the below command to create AWS specific package for this project:

$ ./gradlew clean build
Output
spring-cloud-function-aws-example-1.0-SNAPSHOT-aws.jar

Now we have an artifact ready for the deployment on AWS Lambda.

Deploying the lambda function

We will use gradle-aws-plugin to interact with AWS using gradle.

Deploy Spring Cloud Function to AWS Lambda
task deployFunction(type: AWSLambdaMigrateFunctionTask, dependsOn: [assemble, test]) {
    functionName = "aws-lambda-kotlin-number-reverse"
    runtime = com.amazonaws.services.lambda.model.Runtime.Java8
    role = "arn:aws:iam::${aws.accountId}:role/lambdaDemoRole"

    zipFile = shadowJar.archivePath
    handler = "com.shunya.reverse.Handler"
    memorySize = 512
    timeout = 60
    environment = [
            SPRING_PROFILES_ACTIVE: "dev,aws",
            MAIN_CLASS: "com.shunya.reverse.LambdaApp"
    ]
}

Invoke lambda using gradle plugin

We can use gradle-aws-plugin to invoke lambda function. Firstly we need to create an input json file:

/src/test/resources/sample_request.json
{
  "input": 12345
}
Invoke Lambda Function
task invokeFunction(type: AWSLambdaInvokeTask) {
//    functionName = project.name
    functionName = "aws-lambda-kotlin-number-reverse"
    invocationType = InvocationType.RequestResponse
    payload = file("src/test/resources/sample_request.json")
    doLast {
        println "Lambda function result: " + new String(invokeResult.payload.array())
    }
}
Invoke Gradle Task
$ ./gradlew invokeFunction
gradle output
Lambda function result: {"result":54321}

Alternatively we can use manual approach to create and upload the Lambda function using AWS console.

Setting up AWS CLI

You will have to follow Amazon AWS official documentation to setup AWS CLI on your target platform:

Creating new Lambda Function

Login into AWS Console and select Lambda from the services section. Now create a new Java 8 lambda from scratch as shown in the below screen.

create new lambda

Click on the create function button.

On the next screen, select handler as the below text:

Handler
com.shunya.uppercase.handler.aws.ReverseFunctionHandler

Now upload the artifact created in previous step using upload button.

Create a new execution role from AWS Lambda template for this function.

Configure Test Input

Now we need to test our lambda using input:

configure input

Here we are providing the below json as the input to the lambda:

{
    "input": 12345
}

Lambda Execution

As we can see, we get a reversed number as the response from our lambda function.

lambda output

Invoking lambda using AWS CLI

We can use aws cli to invoke the lambda function, here is the syntax for the same:

$ aws lambda invoke --function-name number-reversal-java --payload '{"input": 23456}' output.txt
Response
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

If response is successful, we can check the output

$ cat output.txt
Output
{ "result": 65432 }

That’s all for this article.

In future we can add other triggers to this lambda function, like API gateway/SQS etc.

Next

In the next article, we will invoke this lambda function from a Java Client using AWS SDK. You can use this approach to invoke AWS lambda from inside a java microservice or another aws lambda function.


Top articles in this category:
  1. Java AWS Lambda using Spring Cloud Function
  2. Invoke AWS Lambda from a Kotlin Client
  3. Invoking AWS Lambda from a Java Client
  4. Feign exception handling in Spring Cloud
  5. Spring Boot Sidecar
  6. Basic Auth Security in Spring Boot 2
  7. S3 File upload & download with AWS Java SDK v2

Recommended books for interview preparation:

Find more on this topic: