AWS Lambda is a product that allows you to upload code, configure a "trigger" for that code, and run the code in Amazon's infrastructure and be billed in 100ms increments for the compute resources. Read more about it here. In this article let's take a look at how we can put some Scala code into AWS.
Set Up Environment
- Log into the AWS Management Console and navigate to IAM.
- Click Users->Find your username, and click on it (or create one)
- Click Security Credentials
- Click Create Access Key
- Note the Access Key and Secret Access Key, you'll need these.
While you're here, let's make an execution role
- Click Roles
- Click Create New Roles
- I'm going to use the name "lambda_basic_execution"
- Choose "select" next to AWS Lambda
- Create a policy
- Find and select AWSLambdaBasicExecutionRole
Ok, that's enough AWS stuff. Let's get your laptop environment going...
Install the AWS Command Line Interface. On a mac with brew, I just typed "brew install awscli".
Now configure the aws command line interface:
$ aws configure
AWS Access Key ID [****************PEPQ]:
AWS Secret Access Key [****************+iVg]:
Default region name [us-west-1]:
Default output format [json]:
The Code
Next, we need to create a project. Create a normal maven project, but be sure to include the following two additions. A plugin:
There is a poorly documented requirement that you return a specially formatted Java Map that represents the HTTP response. This is necessary because not all AWS Lambda functions speak HTTP, but this one does. The Map will be serialized using Jackson by Amazon, so we need to return Java POJO's and Java Collections. Since we're writing Scala, things get a little ugly. Here's a little helper package object to make that easier:
And, finally, our lambda function:
And to deploy the lambda to AWS the first time, just run the following:
Now, click actions->deploy API and you should see the following screen:
On the next screen, you will be given your HTTP endpoint:
Just take that "Invoke URL" and append the resource name to the end, and it should take you to the results of running your Scala code. If you see {"message":"Missing Authentication Token"}, don't forget to add the name of your resource to the URL!
That's it. You've create an HTTP endpoint and linked a "hello world" jar in AWS Lambda and written in Scala to that HTTP endpoint. If you want to add features to your application, just repeat the mvn package step and the use the following code to update the lambda function:
Happy Coding!
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
And a dependency:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.0.0</version>
</dependency>
There is a poorly documented requirement that you return a specially formatted Java Map that represents the HTTP response. This is necessary because not all AWS Lambda functions speak HTTP, but this one does. The Map will be serialized using Jackson by Amazon, so we need to return Java POJO's and Java Collections. Since we're writing Scala, things get a little ugly. Here's a little helper package object to make that easier:
package object gatewayResponse {
def response(response:ResponseCode, body:String, headers:Map[String, String] = Map()):java.util.Map[String, Object] = {
mapAsJavaMap(Map(
"statusCode"-> response.boxed(),
"headers"-> mapAsJavaMap(headers).asInstanceOf[java.util.Map[java.lang.String, java.lang.String]],
"body"-> body)
).asInstanceOf[java.util.Map[java.lang.String, java.lang.Object]]
}
case class ResponseCode(value:Int){
def boxed() = {
Int.box(value)
}
}
val OK = ResponseCode(200)
}
And, finally, our lambda function:
package com.cj.demo
import com.amazonaws.services.lambda.runtime.Context;
import com.cj.lambda.gatewayResponse._
class Demo{
def myHandler(context:Context ) = {
response(OK, "David Says Hello")
}
}
Deployment
To build the code, just run:
mvn package
And to deploy the lambda to AWS the first time, just run the following:
$ aws lambda create-function \
> --function-name scala-lambda-demo \
> --runtime java8 \
> --role arn:aws:iam::727586729164:role/lambda_basic_execution \
> --handler com.cj.demo.Demo::myHandler \
> --zip-file fileb://target/scala-lambda-demo-1.0.jar
Handler
One last one-time step we need to follow is to create an HTTP endpoint and link it to AWS. Do the following:- Navigate once again to the AWS Console.
- Navigate to the API Gateway
- Click "Create API"
- Give the API a name and click "Create API"
- Create a resource, and then inside that resource create a method of type "get".
- Integration type=lambda, use lambda proxy integration, make the region match your previously chosen region, and the lambda function you deployed should auto-complete when you start typing its name. If it doesn't auto-complete, it means that you've either chosen the wrong region or that something went wrong when you used the aws command to create the function.
Now, click actions->deploy API and you should see the following screen:
On the next screen, you will be given your HTTP endpoint:
Just take that "Invoke URL" and append the resource name to the end, and it should take you to the results of running your Scala code. If you see {"message":"Missing Authentication Token"}, don't forget to add the name of your resource to the URL!
That's it. You've create an HTTP endpoint and linked a "hello world" jar in AWS Lambda and written in Scala to that HTTP endpoint. If you want to add features to your application, just repeat the mvn package step and the use the following code to update the lambda function:
aws lambda update-function-code \
--function-name scala-lambda-demo \
--zip-file fileb://target/scala-lambda-demo-1.0.jar
Happy Coding!
This comment has been removed by a blog administrator.
ReplyDelete