AWS Lambda with Go のハンドラ

AWS Lambda を Go で実装するとき、ハンドラを lambda.Start() に渡して実行することが多いと思います。1
lambda.Start() が受け取るハンドラの型は interface{} です。これは empty interface なのでどんな型でも入れることができますが、実際には守らないといけない条件があります。

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

func myHandler() {
        fmt.Println("hello")
}
 
func main() {
        // ハンドラを lambda.Start() に渡す
        lambda.Start(myHandler)
}

ハンドラのシグネチャ

AWS Lambda function handler in Go - AWS Lambda で説明されているように lambda.Start() に渡すハンドラは関数であり、以下のシグネチャである必要があります。 シグネチャを満たさない場合、Lambda 実行時にエラーが発生します

func ()
func () error
func (TIn) error
func () (TOut, error)
func (TIn) (TOut, error)
func (context.Context) error
func (context.Context, TIn) error
func (context.Context) (TOut, error)
func (context.Context, TIn) (TOut, error)

ハンドラの引数

シグネチャにも書いてあるように、ハンドラは引数 TIn を受け取れます。 これにより CloudWatch event などから受け取ったデータをハンドラに渡すことが出来ます。 公式サンプルのハンドラ では events.CloudWatchEvent を受け取っています。

// CloudWatchEvent is the outer structure of an event sent via CloudWatch Events.
// For examples of events that come via CloudWatch Events, see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html
type CloudWatchEvent struct {
    Version    string          `json:"version"`
    ID         string          `json:"id"`
    DetailType string          `json:"detail-type"`
    Source     string          `json:"source"`
    AccountID  string          `json:"account"`
    Time       time.Time       `json:"time"`
    Region     string          `json:"region"`
    Resources  []string        `json:"resources"`
    Detail     json.RawMessage `json:"detail"`
}

func handler(ctx context.Context, event events.CloudWatchEvent) {
    fmt.Printf("Detail = %s\n", event.Detail)
}

TInjson.Unmarshal() に対応している必要があります。 これは外部からの JSON データが []byte から TInjson.Unmarshal() され、ハンドラに渡されるためです。 2
先ほどの events.CloudWatchEventJSON と構造体のフィールドを対応させる tag がついていて、 json.Unmarshal() に対応しています。

外部からの JSON データがハンドラに渡されるまでの流れは以下のページが詳しいです。
https://www.mo4tech.com/aws-lambda-for-go.html

jsonエンコード・デコードついては以下のページが詳しいです。
https://zenn.dev/hsaki/articles/go-convert-json-struct

ハンドラの戻り値

ハンドラは (error) または (TOut, error) の形で結果を返せます。 TOutTIn とは逆に json.Marshal() に対応している必要があります。 3

公式サンプル では (events.APIGatewayProxyResponse, error) で返しています。

// Handler is your Lambda function handler
// It uses Amazon API Gateway request/responses provided by the aws-lambda-go/events package,
// However you could use other event sources (S3, Kinesis etc), or JSON-decoded primitive types such as 'string'.
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

    // stdout and stderr are sent to AWS CloudWatch Logs
    log.Printf("Processing Lambda request %s\n", request.RequestContext.RequestID)

    // If no name is provided in the HTTP request body, throw an error
    if len(request.Body) < 1 {
        return events.APIGatewayProxyResponse{}, ErrNameNotProvided
    }

    return events.APIGatewayProxyResponse{
        Body:       "Hello " + request.Body,
        StatusCode: 200,
    }, nil

}