Create a GO Lambda Function (2023)

To create a GO app the see Chapter Simple programm.

Let`s look at the source in /lambda-go/simple-lambda

  • go.mod
  • go.sum
  • main.go
  • Taskfile.yml
  • testdata / event.json

Main

package main

import (
        "fmt"
        "context"
        "github.com/aws/aws-lambda-go/lambda"
)

type MyEvent struct {
        Name string `json:"name"`
}

func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
        return fmt.Sprintf("Hiho %s!", name.Name ), nil
}

func main() {
        lambda.Start(HandleRequest)
}

  1 package main
  2
  3 import (
  4         "fmt"
  5         "context"
  6         "github.com/aws/aws-lambda-go/lambda"
  7 )
  8
  9 type MyEvent struct {
 10         Name string `json:"name"`
 11 }
 12
 13 func HandleRequest(ctx context.Context, name MyEvent) (string, error) {
 14         return fmt.Sprintf("Hiho %s!", name.Name ), nil
 15 }
 16
 17 func main() {
 18         lambda.Start(HandleRequest)
 19 }

The handler

In line 18 the main function calls the lambda handler. This function is imported in line 6 from “github.com/aws/aws-lambda-go/lambda”.

This handler, here in line 13 is then called with a context and a JSON event.

Lambda call

The input for HandleRequest is a context, from which we can get the lambdacontext. The context stores things like the FunctionName, the AwsRequestID and other things.

The input, which is the payload of the invocation has to be defined in a struct, here MyEvent in line 9.

The event

If you invoke Lambda with an AWS event, all the events are defined in AWS Event definitions.

Working with own events, you define the struct.

So with:

9 type MyEvent struct {
10         Name string `json:"name"`
11 }

the input event could be:

{
  "name": "megaproaktiv"
}

Build & package the app

  1. Build

    env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./dist/main main.go
    

    This takes 0,4 seconds on my computer the output:

    time  env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./dist/main main.go
    env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./dist/main main.go  0,26s user 0,30s system 136% cpu 0,409 total
    
  2. change file execution permission

    chmod +x ./dist/main
    
  3. package the file in a zip

    Lambda upload only accept zipped files, so zip it:

    cd ./dist && zip main.zip main && cd ..
    

    Output:

    updating: main (deflated 60%)
    
Part meaning
env GOOS=linux  build for linux operation system
GOARCH=amd64  build for intel/amd. You need this e.g. if you are working with an M1 mac, which is arm based
go build  build call
-ldflags="-s -w"  See go help build, omit the symbol table, debug information to get a smaller binary
-o ./dist/main  ouput in directory “dist” (short for distribution), file main
main.go  the go file to build

You may need to compile packages with CGO_ENABLED=0 set on Linux.

The build target

With go you can build the binary for different operations systems (os). Without any GOOS/GOARCH GO will take the current os and architecture, so that the app runs on your machine.

With AWS Lambda, the GOOS is always linux. The GOARCH can be amd64 for intel or arm for Gravition.

Deploy the function code

We deploy the code directly from the AWS CLI with:

  1. Deploy with AWS CLI

    aws lambda update-function-code --function-name  gosimple --zip-file fileb://./dist/main.zip
    

    The name gosimple has to be exactly the name you set on the creation of the lambda function.

    Output:

    {
        "FunctionName": "gosimple",
        "FunctionArn": "arn:aws:lambda:eu-central-1:555544443333:function:gosimple",
        "Runtime": "go1.x",
        "Role": "arn:aws:iam::555544443333:role/service-role/gosimple-role-ivx29crw",
        "Handler": "hello",
        "CodeSize": 2380085,
        "Description": "",
        "Timeout": 15,
        "MemorySize": 512,
        "LastModified": "2021-10-31T13:56:03.295+0000",
        "CodeSha256": "JnDGwqj9oKxrb0mwrtLBdi6PaPVkimpMHff0Yb0bPX8=",
        "Version": "$LATEST",
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "RevisionId": "898b0cc5-0ade-43f0-a798-0187d74dea91",
        "State": "Active",
        "LastUpdateStatus": "Successful",
        "PackageType": "Zip",
        "Architectures": [
            "x86_64"
        ]
    }
    

The direct deployment has limits on the file size. Deploy from S3 or with Container images for larger files. See AWS Lambda limits for size limits.

Call the function

In the source code, there is a json file in testdata/event.json. We give the AWS CLI Lambda invoke call the payload event.json as input parameter. Because we use the fileb: function, it does not have to be base64 encoded.

So this call invokes the lambda from the AWS CLI:

aws lambda invoke --function-name gosimple --payload fileb://testdata/event.json testdata/lambda.out

You get the output from the AWS Lambda invoke call as on output:

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

This is not the answer from the Lambda function, but the answer from the Lambda services, which tells you, that the invocation succeeded.

The output from the Lambda function is in `testdata/lambda.out``

cat testdata/lambda.out
"Hiho megaproaktiv!"%

Automating with task

In the source dir there ist the Taskfile.yml.

The calls are included there, so you can:

  1. Deploy

    task deploy
    

For deploy i define a variable NAME, because the function name is often used in the task file. And you can also get this name from AWS Systems Manager Parameter Store or CloudFormation output.

vars:
  NAME: gosimple

 deploy:
    desc: Deploy only Lambda function
    deps: [build]
    cmds:
      - aws lambda update-function-code --function-name  {{.NAME}} --zip-file fileb://./dist/main.zip

This depends on the build task:

  build:
    desc: build go
    cmds:
      - env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./dist/main main.go
      - chmod +x ./dist/main
      - cd ./dist && zip main.zip main
  1. Invoke

    task invoke
    

The creation and deployment with the CDK, see the Chapter Lambda with CDK overview is much better suited for complex deployments. But as you have seen here, the setup for single functions is faster.

See also

Source

See the full source on github.

Sources