Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you invoke a Lambda function within another Lambda function using golang

I'm trying to invoke a lambda func within another lambda func. I have the invokaction of the lambda function working, however, I can't seem to get the consuming lambda function to receive the payload/body from the sending lambda function.

Lambda go doc on invoking a lambda func

Here's my sending/invoking lambda func

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)
}

The response I get from invoked lambda...

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

My consuming lambda function

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)
}

The logs from the consuming lambda func

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

It seems that the consuming lambda function isn't receiving any events.APIGatewayProxyRequest, however I'm not sure why.

EDIT: My solution - I had to also include the json body object in the payload. Here's how I solved it

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.
like image 943
randy Avatar asked Sep 03 '18 16:09

randy


1 Answers

Thanks to @yorodm's input I had to include the body object into the payload as well.

Here is the full solution to invoke a lambda function within another lambda function using golang

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
like image 69
randy Avatar answered Oct 06 '22 23:10

randy