如何使用golang在另一个Lambda函数中调用Lambda函数

时间:2018-09-03 16:48:49

标签: amazon-web-services go aws-lambda aws-sdk

我正在尝试在另一个Lambda函数中调用Lambda函数。我可以使用lambda函数,但是,似乎无法从使用的lambda函数中接收发送的lambda函数的有效负载/主体。

Lambda go doc on invoking a lambda func

这是我的发送/调用lambda函数

type Response events.APIGatewayProxyResponse

func Handler(ctx context.Context) (Response, error) {
    region := os.Getenv("AWS_REGION")
    session, err := session.NewSession(&aws.Config{ // Use aws sdk to connect to dynamoDB
        Region: &region,
    })
    svc := invoke.New(session)

    payload, err := json.Marshal(map[string]interface{}{
        "message": "message to other lambda func",
    })

    if err != nil {
        fmt.Println("Json Marshalling error")
    }
    input := &invoke.InvokeInput{
        FunctionName:   aws.String("invokeConsume"),
        InvocationType: aws.String("RequestResponse"),
        LogType:        aws.String("Tail"),
        Payload:        payload,
    }
    result, err := svc.Invoke(input)
    if err != nil {
        fmt.Println("error")
        fmt.Println(err.Error())
    }
    var m map[string]interface{}
    json.Unmarshal(result.Payload, &m)
    fmt.Println(m["body"])

    body, err := json.Marshal(m["body"])
    resp := Response{
        StatusCode:      200,
        IsBase64Encoded: false,
        Headers: map[string]string{
            "Content-Type": "application/json",
        },
        Body: string(body),
    }
    fmt.Println(resp)

    return resp, nil
}
func main() {
    lambda.Start(Handler)
}

我从被调用的lambda得到的响应...

{200 map[Content-Type:application/json] "{\"message\":\"Something\"}" false} 

我正在使用的lambda函数

type Response events.APIGatewayProxyResponse

func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (Response, error) {
    fmt.Println(req)

    var m map[string]interface{}
    err := json.Unmarshal([]byte(req.Body), &m)
    if err != nil {
        fmt.Println("Json Unmarshalling error")
        fmt.Println(err.Error())
    }
    fmt.Println(m)

    body, _ := json.Marshal(map[string]interface{}{
        "message": "Something",
    })
    resp := Response{
        StatusCode:      200,
        IsBase64Encoded: false,
        Headers: map[string]string{
            "Content-Type": "application/json",
        },
        Body: string(body),
    }
    return resp, nil
}
func main() {
    lambda.Start(Handler)
}

使用中的lambda函数的日志

{ map[] map[] map[] map[] { { } map[] } false}
Json Unmarshalling error
unexpected end of JSON input
map[]

似乎使用中的lambda函数没有收到任何事件。APIGatewayProxyRequest,但是我不确定为什么。

编辑: 我的解决方案-我还必须在有效负载中包含json主体对象。这是我解决的方法

body, err := json.Marshal(map[string]interface{}{
    "name": "Jimmy",
})
type Payload struct {
    Body string `json:"body"`
}
p := Payload{
    Body: string(body),
}
payload, err := json.Marshal(p) // This should give you {"body":"{\"name\":\"Jimmy\"}"} if you print it out which is the required format for the lambda request body.

4 个答案:

答案 0 :(得分:2)

问题似乎是您没有将适当的API网关代理请求事件传递给您的使用者lambda:

如果您查看MDN,您会发现API Gateway事件具有以下结构(或多或少)

{
  "path": "/test/hello",
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, lzma, sdch, br",
    "Accept-Language": "en-US,en;q=0.8",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
    "Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
    "X-Forwarded-For": "192.168.100.1, 192.168.1.1",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "pathParameters": {
    "proxy": "hello"
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "us4z18",
    "stage": "test",
    "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
    "identity": {
      "cognitoIdentityPoolId": "",
      "accountId": "",
      "cognitoIdentityId": "",
      "caller": "",
      "apiKey": "",
      "sourceIp": "192.168.100.1",
      "cognitoAuthenticationType": "",
      "cognitoAuthenticationProvider": "",
      "userArn": "",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
      "user": ""
    },
    "resourcePath": "/{proxy+}",
    "httpMethod": "GET",
    "apiId": "wt6mne2s9k"
  },
  "resource": "/{proxy+}",
  "httpMethod": "GET",
  "queryStringParameters": {
    "name": "me"
  },
  "stageVariables": {
    "stageVarName": "stageVarValue"
  }
}

如您所见,大多数字段都与HTTP相关,这是因为API网关是一种将lambda函数公开到网络的方法(也称为make REST APIS)。您可以更改lambda以接受新的事件类型(它必须是JSON可序列化的类型),也可以用作字符串并自己对其进行序列化。

答案 1 :(得分:2)

我认为您需要确保选择Use lambda proxy integration,这样您才能接收有效载荷数据。

API Gateway integration

答案 2 :(得分:0)

由于@yorodm的输入,我还必须将主体对象也包含在有效载荷中。

这是使用golang在另一个lambda函数中调用lambda函数的完整解决方案

region := os.Getenv("AWS_REGION")
session, err := session.NewSession(&aws.Config{ // Use aws sdk to connect to dynamoDB
    Region: &region,
})
svc := invoke.New(session)

body, err := json.Marshal(map[string]interface{}{
    "name": "Jimmy",
})

type Payload struct {
    // You can also include more objects in the structure like below, 
    // but for my purposes body was all that was required
    // Method string `json:"httpMethod"`
    Body string `json:"body"`
}
p := Payload{
    // Method: "POST",
    Body: string(body),
}
payload, err := json.Marshal(p) 
 // Result should be: {"body":"{\"name\":\"Jimmy\"}"} 
 // This is the required format for the lambda request body.

if err != nil {
    fmt.Println("Json Marshalling error")
}
fmt.Println(string(payload))

input := &invoke.InvokeInput{
    FunctionName:   aws.String("invokeConsume"),
    InvocationType: aws.String("RequestResponse"),
    LogType:        aws.String("Tail"),
    Payload:        payload,
}
result, err := svc.Invoke(input)
if err != nil {
    fmt.Println("error")
    fmt.Println(err.Error())
}
var m map[string]interface{}
json.Unmarshal(result.Payload, &m)
fmt.Println(m["body"])

invokeReponse, err := json.Marshal(m["body"])
resp := Response{
    StatusCode:      200,
    IsBase64Encoded: false,
    Headers: map[string]string{
        "Content-Type": "application/json",
    },
    Body: string(invokeReponse),
}
fmt.Println(resp)

return resp, nil

答案 3 :(得分:0)

AWS SDK 有一个例子: https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/go/example_code/lambda/aws-go-sdk-lambda-example-run-function.go

package main

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/lambda"
    
    "encoding/json"
    "fmt"
    "os"
    "strconv"
)

type getItemsRequest struct {
    SortBy     string
    SortOrder  string
    ItemsToGet int
}

type getItemsResponseError struct {
    Message string `json:"message"`
}

type getItemsResponseData struct {
    Item string `json:"item"`
}

type getItemsResponseBody struct {
    Result string                 `json:"result"`
    Data   []getItemsResponseData `json:"data"`
    Error  getItemsResponseError  `json:"error"`
}

type getItemsResponseHeaders struct {
    ContentType string `json:"Content-Type"`
}

type getItemsResponse struct {
    StatusCode int                     `json:"statusCode"`
    Headers    getItemsResponseHeaders `json:"headers"`
    Body       getItemsResponseBody    `json:"body"`
}

func main() {
    // Create Lambda service client
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    client := lambda.New(sess, &aws.Config{Region: aws.String("us-west-2")})

    // Get the 10 most recent items
    request := getItemsRequest{"time", "descending", 10}

    payload, err := json.Marshal(request)
    if err != nil {
        fmt.Println("Error marshalling MyGetItemsFunction request")
        os.Exit(0)
    }

    result, err := client.Invoke(&lambda.InvokeInput{FunctionName: aws.String("MyGetItemsFunction"), Payload: payload})
    if err != nil {
        fmt.Println("Error calling MyGetItemsFunction")
        os.Exit(0)
    }

    var resp getItemsResponse

    err = json.Unmarshal(result.Payload, &resp)
    if err != nil {
        fmt.Println("Error unmarshalling MyGetItemsFunction response")
        os.Exit(0)
    }

    // If the status code is NOT 200, the call failed
    if resp.StatusCode != 200 {
        fmt.Println("Error getting items, StatusCode: " + strconv.Itoa(resp.StatusCode))
        os.Exit(0)
    }

    // If the result is failure, we got an error
    if resp.Body.Result == "failure" {
        fmt.Println("Failed to get items")
        os.Exit(0)
    }

    // Print out items
    if len(resp.Body.Data) > 0 {
        for i := range resp.Body.Data {
            fmt.Println(resp.Body.Data[i].Item)
        }
    } else {
        fmt.Println("There were no items")
    }
}