AWS Lambda is an event-driven, serverless computing platform by Amazon. You can run your code without provisioning or managing a servers using AWS Lambda. You are charged only for the computing resources actually consumed, which is metered in the multiple of 100 milliseconds. Java, Node.js, C# and Python - are officially supported languages for writing Lambda. If you want to write Lambda in language not supported officially, it could be executed through a thin Node.Js wrapper. I this post, I will show how to write the Lambda in Golang. A Lambda could be executed in response to events like changes in the AWS S3 bucket(i.e. video, image, document processing), changes in DynamoDB table(i.e. data processing, analysis), in response to IoT device events, etc. A Lambda could also be exposed as an API to be consumed by your mobile apps, integration layer or clients.
Here is why I think Lambda could be a really powerful tool for many use cases:
- (a) No devops/ servers to manage -just write the code to do what you need to, it removes lots of friction
- (b) It’s executed in high-availability compute infrastructure
- (c) It could be scaled easily with vast computing power available at AWS
- (d) Pay for what you used - not need to pay for that extra computing power to deal with spikes in usage
You could write code directly in the AWS console or upload a zip file in S3 bucket. You could specify the amount of memory, maximum execution time, etc. while creating Lambda. When Lambda is invoked, AWS launches an execution environment(sort of a container) base on those settings. These containers are cached for subsequent executions. The default limit on the number of parallel executions is 100, you could request to increase this limit.
Let’s Write Lambda In Golang
Go compiles to single binary and is known for fast execution, which makes it a good candidate to write Lambda in. Golang isn’t officially supported language for writing Lambda yet, but the Node.js wrapper could invoke the executable. You could write a thin Node.js wrapper to invoke the executable, however tool like Sparta makes it even easier and provides additional features like cross compiling for Linux, deployment, local testing, etc. I will use Sparta in this post.
Sparta provides a Main
function that transforms your lambda functions into an application. This function should be called from your application’s main
package. Let’s write a Lambda for generating QR Code. As you can see qrGenerator
is configured as a Lambda function by calling sparta.NewLambda
in the main
call:
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/Sirupsen/logrus"
sparta "github.com/mweagle/Sparta"
qrcode "github.com/skip2/go-qrcode"
)
//This is our Lambda
func qrGenerator(event *json.RawMessage,
context *sparta.LambdaContext,
w http.ResponseWriter,
logger *logrus.Logger) {
//Read the event info - we could access Body, Headers, QueryParams, PathParams, Method, etc.
var lambdaEvent sparta.APIGatewayLambdaJSONEvent
errEvent := json.Unmarshal([]byte(*event), &lambdaEvent)
if errEvent != nil {
logger.Error("Failed to unmarshal event data: ", errEvent.Error())
http.Error(w, errEvent.Error(), http.StatusInternalServerError)
return
}
//Read the QRRequest
//fmt.Printf("Request: %s", lambdaEvent.Body)
var qrRequest QRCodeRequest
errRequest := json.Unmarshal(lambdaEvent.Body, &qrRequest)
if errRequest != nil {
logger.Error("Error reading the QR Code request: ", errRequest.Error())
http.Error(w, errRequest.Error(), http.StatusInternalServerError)
return
}
//Create the QR image
var png []byte
png, err := qrcode.Encode(qrRequest.QRText, qrcode.Medium, 256)
if err != nil {
fmt.Printf("Error: %s", err)
}
//logger.Info("QR Generator: ", string(*event)) //<-- Logging could be helpful for troubleshooting
result, err := json.Marshal(OperationResult{
Success: true,
Data: QRCode{
QRText: qrRequest.QRText,
Image: png},
Message: "Successfully generated the QR Code."})
if err != nil {
logger.Panic("Error: %s", err)
panic(err)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(result))
}
func main() {
var lambdaFunctions []*sparta.LambdaAWSInfo
//Configure our Lambda to expose it
lambdaFn := sparta.NewLambda(sparta.IAMRoleDefinition{}, qrGenerator, nil)
lambdaFunctions = append(lambdaFunctions, lambdaFn)
sparta.Main("QRGenerator", "QR Code Utilities", lambdaFunctions, nil, nil)
}
//Just a reusable response wrapper
type OperationResult struct {
Success bool
Message string
Data interface{}
}
//QRCode response - more details could be added
type QRCode struct {
QRText string
Image []byte
}
//QRCode Request details
type QRCodeRequest struct {
QRText string `json:"qrtext"`
}
Once you compiled, Sparta make following commands available to your executable.
delete Delete service
describe Describe service
execute Execute
explore Interactively explore service
provision Provision service
version Sparta framework version
Running ./lambdaGo explore
will start a local web server and expose your Lambda for testing. You could use curl or Postman to invoke it.
Let’s Deploy It
Sparta uses AWS SDK for provisioning the Lambda, so you need to configure your credentials, region, etc. You can get more information about creating credential file and role from here. You could set the region through environment variable by running export AWS_REGION=us-east-2
, make sure this region matches with your bucket’s region. Once you have credentials and region in place, you could run the command ./lambdaGo provision -s <your-bucket-name>
to start the provisioning Lambda to AWS. Once deployed to AWS, you will be able to see your Lambda on console and test it
Let’s Expose Lambda as API
Our Lambda is there up in the cloud, but we haven’t configured any triggers or exposed as an API. Let’s use AWS API Gateway to expose it as API. Go to the API Gateway on AWS console and follow the steps for creating an API to execute the Lambda we created in previous step
There are multiple ways to secure your API. I have secured it through the API key and have also created usage plan to limit the number of invocations/ month. Once everything is configured, you could test the set up by invoking through curl or Postman. Make sure to pass the authorization information and/or API key based on your configuration.
AWS console also provides monitoring and logging features.