It is simple when it comes to handling a single AWS Lambda function in your application but handling multiple ones could be slightly complex. In this example we are going to adopt a strategy in order to work out which handler the event was meant to be passed onto. Here the main handler looks into the actual request. It then checks the value from the event key and pass the encoded value from the body key to a relevant function.


Files


main.go


package main

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

func main() {
lambda.Start(user.User{}.Handle)
}

user/user.go


package user

import (
"context"
"encoding/json"
"fmt"

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

type HandleRequest struct {
Event string `json:"event"`
Body json.RawMessage `json:"body"`
}

type HandleResponse struct {
OK bool `json:"ok"`
ReqID string `json:"req_id"`
}

type User struct {
// Some dependencies
}

func (u User) Handle(ctx context.Context, req HandleRequest) (interface{}, error) {
var reqID string
if lc, ok := lambdacontext.FromContext(ctx); ok {
reqID = lc.AwsRequestID
}

select {
case <-ctx.Done():
return HandleResponse{OK: false, ReqID: reqID}, fmt.Errorf("request timeout: %w", ctx.Err())
default:
}

switch req.Event {
case "create":
var dest CreateRequest
if err := json.Unmarshal(req.Body, &dest); err != nil {
return nil, err
}
return u.Create(ctx, reqID, dest)
case "delete":
var dest DeleteRequest
if err := json.Unmarshal(req.Body, &dest); err != nil {
return nil, err
}
return u.Delete(ctx, reqID, dest)
}

return HandleResponse{OK: false, ReqID: reqID}, fmt.Errorf("%s is an unknown event", req.Event)
}

user/create.go


package user

import (
"context"
"fmt"
"time"
)

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"`
}

func (u User) Create(_ context.Context, reqID string, req CreateRequest) (CreateResponse, error) {
if req.FirstName == "" {
return CreateResponse{OK: false, ID: 0, ReqID: reqID}, fmt.Errorf("the first_name is missing")
}
if req.LastName == "" {
return CreateResponse{OK: false, ID: 0, ReqID: reqID}, fmt.Errorf("the last_name is missing")
}

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

user/delete.go


package user

import (
"context"
"fmt"
)

type DeleteRequest struct {
ID string `json:"id"`
}

type DeleteResponse struct {
OK bool `json:"ok"`
ReqID string `json:"req_id"`
}

func (u User) Delete(_ context.Context, reqID string, req DeleteRequest) (DeleteResponse, error) {
if req.ID == "" {
return DeleteResponse{OK: false, ReqID: reqID}, fmt.Errorf("the id key is missing")
}

return DeleteResponse{OK: true, ReqID: reqID}, nil
}

Test


// Setup
$ GOOS=linux CGO_ENABLED=0 go build -ldflags "-s -w" -o app main.go
$ zip app.zip app
$ 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"

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

// create.json: {"id":1640808733146866600,"ok":true,"req_id":"c39c8a10-1c19-11e1-6810-d0f60acc866a"}

// Delete
$ aws --profile localstack --endpoint-url http://localhost:4566 lambda invoke --function-name user-create --cli-binary-format raw-in-base64-out --payload '{"event":"delete","body":{"id":"idx"}}' delete.json

// delete.json: {"ok":true,"req_id":"54790f38-268b-1a30-9406-6cbfe0fb2db0"}