request.Body has a different value through http gateway than through the test GUI

Viewed 29

I got this code from https://github.com/aws/aws-lambda-go/blob/master/events/README_ApiGatewayEvent.md :

package main

import (
    "context"
    "fmt"
    "log"

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

func handleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    fmt.Printf("Processing request data for request %s.\n", request.RequestContext.RequestID)
    fmt.Printf("Body size = %d.\n", len(request.Body))

    fmt.Println("Headers:")
    for key, value := range request.Headers {
        fmt.Printf("    %s: %s\n", key, value)
    }

    log.Printf("%v", request.Body)

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

func main() {
    lambda.Start(handleRequest)
}

I only added: the log: log.Printf("%v", request.Body)

When I compile and use the lambda test GUI, I send this:

{"body":"[{\"id\":\"123\"}]"}

and the log in the tab shows this:

2021/08/16 08:51:50 [{"id":"123"}]

However, when I do this:

curl https://qmk743l1p0.execute-api.us-east-1.amazonaws.com/default/simplegateway -d '{"body":"[{\"id\":\"123\"}]"}' --header "Content-Type: application/json"

I get this in the CloudWatch logs:

2021/08/16 08:56:07 {"body":"[{\"id\":\"123\"}]"} 

I have no idea why request.body would have two different values when going through the http gateway.

How do I get the intended "body" in both the lambda test GUI and in through the http API gateway?

2 Answers

This happens because your handler has the same signature in both cases, but what that implies differs based on what is proxying your request.

When you send the request from the Lambda GUI, the body gets unmarshaled into the events.APIGatewayProxyRequest straight away. That struct has a field defined as:

Body string `json:"body"`

So when you send the payload {"body":"[{\"id\":\"123\"}]"}, json.Unmarshal populates that field with the value of the JSON body property, which is [{"id":"123"}]

When the same request is proxied through the API Gateway, the Gateway constructs a AWS event that contains your payload as-is, so it will probably look like:

{
    ...
    "body": "{\"body\":\"[{\"id\":\"123\"}]\"}\"
}

And only then the event is unmarshaled into the events.APIGatewayProxyRequest struct, resulting in the Body field having the value {"body":"[{\"id\":\"123\"}]"}.

Though i am not familiar with the lambda GUI i suspect that there you input the json representation of the request (with headers and body), but when sending via curl, you don't need to wrap the body (-d), so just send it like this [{\"id\":\"123\"}] as this is what the body should contain.

Related