In this example we are going to create a Golang application where there is a single AWS Lambda handler. The function will be in zip form and accepting a JSON request. There will also be a JSON response which will be written into a file. For all these operations we will use a Localstack instance. For more info visit AWS Lambda CLI page.


Prerequisites


Setup your docker compose file using the content below and run it. After running it, pull lambci/lambda:go1.x docker image in order to work with Lambda using Localstack.


version: "2.1"

services:
localstack:
image: "localstack/localstack"
container_name: "localstack"
ports:
- "4566-4599:4566-4599"
environment:
- DEBUG=1
- DEFAULT_REGION=eu-west-1
- SERVICES=lambda
- DATA_DIR=/tmp/localstack/data
- DOCKER_HOST=unix:///var/run/docker.sock
# - LAMBDA_EXECUTOR=docker
volumes:
- "/tmp/localstack:/tmp/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"

Files


main.go


package main

import (
"github.com/aws/aws-lambda-go/lambda"
"github.com/you/user"
)

func main() {
lambda.Start(user.Create)
}

user/create.go


package user

import (
"context"
"fmt"
"time"

"github.com/aws/aws-lambda-go/lambdacontext"
)

type CreateRequest struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}

type CreateResponse struct {
OK bool `json:"ok"`
ID int64 `json:"id"`
ReqID string `json:"req_id"`
}

// Create creates a new user and returns its ID. If the request context was
// cancelled/timed out before proceeding to run the business logic, it will
// return an error. The timeout can be found in `Timeout` parameter of the lambda
// function. Defaults to 3 sec.
func Create(ctx context.Context, request CreateRequest) (CreateResponse, error) {
select {
case <-ctx.Done():
return CreateResponse{OK: false, ID: 0}, fmt.Errorf("request timeout: %w", ctx.Err())
default:
}

var reqID string
if lc, ok := lambdacontext.FromContext(ctx); ok {
reqID = lc.AwsRequestID
}

if request.FirstName == "" || request.LastName == "" {
return CreateResponse{OK: false, ID: 0, ReqID: reqID}, fmt.Errorf("missing first or last name")
}

return CreateResponse{OK: true, ID: time.Now().UnixNano(), ReqID: reqID}, nil
}

Setup


Build binary


// I am using MacOS
$ GOOS=linux CGO_ENABLED=0 go build -ldflags "-s -w" -o app main.go

Zip binary


$ zip app.zip app

Create function


$ aws --profile localstack --endpoint-url http://localhost:4566 lambda create-function --function-name user-create --handler app --zip-file fileb://app.zip --runtime go1.x --role some-role --description "Creates a new user"

{
"FunctionName": "user-create",
"FunctionArn": "arn:aws:lambda:eu-west-1:000000000000:function:user-create",
"Runtime": "go1.x",
"Role": "some-role",
"Handler": "app",
"CodeSize": 2380470,
"Description": "Creates a new user",
"Timeout": 3,
"LastModified": "2021-12-29T17:12:57.199+0000",
"CodeSha256": "chRYxmVCd5ufDOrxui3kAUJZsCcp6WZn4LsMElZHIRg=",
"Version": "$LATEST",
"VpcConfig": {},
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "db7a03d0-cbda-4081-8b1a-0dc598c4ea34",
"State": "Active",
"LastUpdateStatus": "Successful",
"PackageType": "Zip"
}

Invoke function


$ aws --profile localstack --endpoint-url http://localhost:4566 lambda invoke --function-name user-create --cli-binary-format raw-in-base64-out --payload '{"first_name":"fn","last_name":"ln"}' response.json

{
"StatusCode": 200,
"LogResult": "",
"ExecutedVersion": "$LATEST"
}

response.json


{
"id": 1640804522226871000,
"ok": true,
"req_id": "773348c7-ed62-14de-8232-07a52eca3215"
}