# AWS Lambda function in Scala with Container Image

In this post, I will describe how you can write your code in Scala, package it in a Docker Container, and run it serverless with AWS Lambda.

## Scala project

First, create a Scala project using [sbt](https://www.scala-sbt.org/) as the build tool. I have created a [github repository](https://github.com/codiply/lambda-container-scala-example) with the final result at the end of this post.

## Creating a Fat Jar

AWS Lambda does not offer a runtime for Scala. However, I can create a fat Jar and run it with the Java runtime. This works, because a fat Jar is built with all the project dependencies packaged in one big Jar, including all Scala libraries.

I install the `sbt-assembly` plugin by adding the following line to `project/plugins.sbt`

```scala
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0")
```

and in `build.sbt` I set the filename of the fat Jar to something that does not depend on the project name or Scala version

```scala
assembly / assemblyOutputPath := file("target/function.jar")
```

Now, I can create the fat jar by simply typing

```bash
sbt assembly
```

but there is no need to do this step manually because I will do this within docker.

## Creating the handler

For the handler, I adapt the Java code from [this example](https://github.com/awsdocs/aws-lambda-developer-guide/blob/main/sample-apps/java-basic/src/main/java/example/Handler.java) and I get the following.

```scala
package com.example

import java.util.{ Map => JavaMap }
import com.amazonaws.lambda.thirdparty.com.google.gson.GsonBuilder
import com.amazonaws.services.lambda.runtime.{Context, RequestHandler}

class LambdaHandler() extends RequestHandler[JavaMap[String, String], String] {
  val gson = new GsonBuilder().setPrettyPrinting.create

  override def handleRequest(event: JavaMap[String, String], context: Context): String = {
    val logger = context.getLogger

    logger.log(s"ENVIRONMENT VARIABLES: ${gson.toJson(System.getenv)}\n")
    logger.log(s"CONTEXT: ${gson.toJson(context)}\n")

    logger.log(s"EVENT: ${gson.toJson(event)}\n")

    "Hello from Scala!"
  }
}
```

## Create the Dockerfile

I add a `Dockerfile` at the root of the project

```dockerfile
FROM mozilla/sbt as builder
COPY . /lambda/src/
WORKDIR /lambda/src/
RUN sbt assembly

FROM public.ecr.aws/lambda/java:11
COPY --from=builder /lambda/src/target/function.jar ${LAMBDA_TASK_ROOT}/lib/
CMD ["com.example.LambdaHandler::handleRequest"]
```

What I am doing here is the following

* I am using a multi-stage build to build the fat Jar with sbt
    
* Then I start using the official AWS docker image for lambda in Java
    
* I copy over the fat Jar only
    
* You will need to modify the `CMD` to the full name of your class and method
    

## Build and publish the image

In what follows, you need to replace `<aws-region>` and `<aws-account-number>` with your selected region and your account number. I am assuming that you have installed the [AWS CLI](https://aws.amazon.com/cli/) and have configured your credentials.

I create a repository in Amazon ECR called `lambda-scala-example`

```bash
aws ecr create-repository --region <aws-region> --repository-name lambda-scala-example
```

I login to ECR with docker

```bash
aws ecr get-login-password --region <aws-region> | docker login --username AWS --password-stdin <aws-account-number>.dkr.ecr.<aws-region>.amazonaws.com
```

I build and tag the image

```bash
docker build . -t <aws-account-number>.dkr.ecr.<aws-region>.amazonaws.com/lambda-scala-example
```

Finally, I push the image

```bash
docker push <aws-account-number>.dkr.ecr.<aws-region>.amazonaws.com/lambda-scala-example
```

I can now see the image in ECR in the AWS Management Console (in the selected region)

![ecr.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625392546246/bmJuvm72_.png align="left")

## The lambda function

I navigate to AWS Lambda in the same AWS region and I create a new function

![2-create-lambda.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625392714064/ce2egcySD.png align="left")

I select the option `Container image` and enter a name. Then, I press `Browse images` to locate the container image URI

![3.select-container-image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625392780372/9YEbr45Y6.png align="left")

I select the image, leave all optional settings as they are and I create the function

## Test the function

I test the function and it runs successfully

![4-test-function.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625392902172/jIFdnqYlp.png align="left")

## Conclusion

If Scala is your preferred language, you can easily use it with Lambda functions to create serverless microservices.

The complete example project can be found in [this github repository](https://github.com/codiply/lambda-container-scala-example).
