EDIT: Well as of writing this thing I found out that 1# I didn't deploy my changes, embarrassingly and 2# It worked. Now I just have to stringify the JSON back with the added field.
10 minutes later: Well that was hard... So instead I found this which worked:
#set($payload = $util.parseJson($input.json('$')))
#set($body = "{
#foreach ($mapEntry in $payload.entrySet())
""$mapEntry.key"": ""$mapEntry.value"",
#end
""timeReceived"": ""$context.requestTime"",
""x-client-ip"": ""$context.identity.sourceIp""
}")
But which expanded the JSON to multiple lines (the JSON is sent to Firehose which then stores it to S3) which is no good.
20 minutes later: My senior dev laughed at me when I told him what I was doing and commented API Gateway Mapping Templates with couple expletives.
40 minutes later: I knew what I had to do: replace all newline characters with empty strings but that proved to be harder than I thought. Also I found out that my nested values inside the object weren't stringified.
50 minutes later: Well actually I can omit the newline replacement by just having the whole foreach-loop in single line. But again I have to somehow stringify the nested values. And the requestTime
is formatted in some stupid english format (no offense! :))
70 minutes later: Formatting correctly the nested values is really difficult. I found another example which worked:
#set($body = "{
#foreach ($mapEntry in $payload.entrySet())
#if ($mapEntry.value.size() > 0)
""$mapEntry.key"": {
#foreach($subEntry in $mapEntry.value.entrySet())
""$subEntry.key"": ""$subEntry.value""#if($foreach.hasNext),#end
#end
},
#else
""$mapEntry.key"": ""$mapEntry.value"",
#end
#end
""timeReceived"": $context.requestTimeEpoch}
}")
Which translates to if you don't want new lines or extra spaces into this:
#set($body = "{#foreach ($mapEntry in $payload.entrySet())#if($mapEntry.value.size() > 0)""$mapEntry.key"": { #foreach($subEntry in $mapEntry.value.entrySet())""$subEntry.key"": ""$subEntry.value""#if($foreach.hasNext), #end#end }, #else""$mapEntry.key"": ""$mapEntry.value"", #end#end""timeReceived"": $context.requestTimeEpoch }" )
120 minutes spent both debugging and writing this: Well that was a journey. I guess I already answered my own question so hopefully now someone can avoid spending so much time debugging this as I did.
130 minutes later: Aaand now I have to solve the tragedy of adding that string into my CloudFormation template. Oh boy. (Which wasn't even hard, the hard part is redeploying the API gateway which as of writing this I had to do manually from the console)