Search code examples
amazon-web-servicesgoaws-lambdaaws-event-bridge

AWS EventBridge PutEvent Detail Malformed


I have tried both AWS Go SDKs both versions and every time I get an error stating that the Details field is malformed. The Details field accepts a JSON string.

In SDK V2 you basically have a struct for the event

type Event struct {
Details []struct {
    Key   string `json:"Key"`
    Value string `json:"Value"`
} `json:"Details"`
DetailType string `json:"DetailType"`
Source     string `json:"Source"`

}

The example then builds up the JSON string with this code

myDetails := "{ "
for _, d := range event.Details {
    myDetails = myDetails + "\"" + d.Key + "\": \"" + d.Value + "\","
}

myDetails = myDetails + " }"

And then make the api call

input := &cloudwatchevents.PutEventsInput{
    Entries: []types.PutEventsRequestEntry{
        {
            Detail:     &myDetails,
            DetailType: &event.DetailType,
            Resources: []string{
                *lambdaARN,
            },
            Source: &event.Source,
        },
    },
}

Basically I get an error saying that the string assigned to the Detail field is malformed. I believe this is because the example code generates a string with a trailing which is not valid . However when you omit the , you get a nil memory reference.

AWS SDK Example

The example for SDK version 1 also generates an error.
Any help would be great


Solution

  • The code on the page you linked is not 100% correct. They actually link the "complete example" at the bottom of the page, which has slightly different code:

    https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/gov2/cloudwatch/PutEvent/PutEventv2.go#L108-L117

    myDetails := "{ "
    for i, d := range event.Details {
        if i == (len(event.Details) - 1) {
            myDetails = myDetails + "\"" + d.Key + "\": \"" + d.Value + "\""    
        } else {
            myDetails = myDetails + "\"" + d.Key + "\": \"" + d.Value + "\","
        }
    }
    
    myDetails = myDetails + " }"
    

    But building the JSON like this is not ideal and error-prone, as you already found out.

    I'd propose the following:

    details := make(map[string]string, len(event.Details))
    for _, d := range event.Details {
        details[d.Key] = d.Value
    }
    
    b, err := json.Marshal(details)
    if err != nil {
        return
    }
    
    fmt.Println(string(b))
    

    Checkout the playground to see it in action:

    https://play.golang.com/p/E4ueZLGIKp4