如何使用Localstack在Golang中处理多个AWS Lambda处理程序

95 阅读2分钟

多年来,我们一直投入大量的个人时间和精力,与大家分享我们的知识。然而,我们现在需要你的帮助来维持这个博客的运行。你所要做的只是点击网站上的一个广告,否则它将由于托管等费用而不幸被关闭。谢谢你。

当涉及到在你的应用程序中处理一个AWS Lambda函数时,这很简单,但处理多个函数可能会略显复杂。在这个例子中,我们将采用一种策略,以找出事件要传递给哪个处理程序。在这里,主处理程序查看了实际的请求。然后它检查来自event 键的值,并将来自body 键的编码值传递给一个相关的函数。

文件

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
}

测试

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