JD Stuart
JD Stuart

Reputation: 557

Acces variable in JSONPath API Gateway Body Mapping

Using AWS's API Gateway I configured an api resource as an AWS proxy to Kinesis' PutRecords action. The API consumers send me a list of events I need to forward those events to a Kinesis stream.

The format in which they send the data to the API gateway look something similar to this. It contains 1 top level element that's of type Array. The object type of each array item is a JSON document:

{
    "events":[
        {
            "time":"2017-01-01T11:43:21",
            "type":"ItemSelected",
            "application":"iOS Build 3654"
        },{
            "time":"2017-01-01:11:55:32",
            "type":"ItemSelected",
            "application":"iOS Build 3654"
        }
    ]
}

What's needed is to break each separate event into a Kinesis record and send it to as a base64Encoded string to Kinesis.

Using a Body Mapping Template I've configured the following.

{
    "StreamName":"MemberApiAuditLog",
    "Records":[
        #foreach($elem in $input.path('$.events')){
        #set($countVal=$foreach.count-1)
            "Data":"$util.base64Encode($input.json('$.events[$countVal]'))",
            "PartitionKey":"$input.path('$.memberid')"
        }
        #end
    ]
}

The problem I'm having is that the Mapping Template doesn't seem to have an issue with this the $countVal variable in this code: '$.events[$countVal]'. It somehow just doesn't recognize the $countVal. If I replace $countVal with 0, it works just fine.

I need to use $input.json(x) because the mapping template doesn't provide a different way to stringify a json object.

Questions:

  1. Other than $input.json(x) is there a way to stringify a json object in a Body Mapping Template?
    1. I've tried JSON.stringify(object), but that didn't work.
  2. How can I get the code to recognize the value of countVal in that expression? If that can be resolved, the issue will be solved.

Upvotes: 7

Views: 2875

Answers (3)

Jason Capriotti
Jason Capriotti

Reputation: 2060

One of the previous examples helped me understand how to fix this type of problem, so wanted to call out solution in a different way.

I think the single quotes around your $.events[$countVal] is causing the problem. Double quotes are needed for proper interpolation, so splitting up the assignment makes it clearer and avoids any escaping/quoting confusion or issues.

## Note the double quotes
#set($json = $input.json("$.events[$foreach.index]"))

"Data":"$util.base64Encode($json)"

The VTL documentation also helped me out:

# [ { ] set [ } ] ( $ref = [ ", ' ] arg [ ", ' ] )

arg is parsed (i.e. interpolated) if enclosed in double quotes, and not parsed if enclosed in single quotes

Upvotes: 0

kanedaki
kanedaki

Reputation: 306

I've manage to make the template work, creating a valid json object.

{
    "streamName": "MemberApiAuditLog",
    "Records": [
        #set($inputRoot = $input.path('$.events'))
        #foreach($elem in $inputRoot) {
           #set($json = $input.json("$[$foreach.index]"))
            "Data":"$util.base64Encode($json)",
        #end
    ]
}

It works for me, hope for you too

Upvotes: 7

Jurgen
Jurgen

Reputation: 1273

You do not need to convert the objects into strings in the foreach loop. Instead, you should be able to simply pass the object to the base64Encode function which automatically converts it into a base64 string.

The following mapping template produced the output below:

{
    "StreamName":"MemberApiAuditLog",
    "Records":[
        #foreach($elem in $input.path('$.events')){
            "Data":"$util.base64Encode($elem)",
            "PartitionKey":"$input.path('$.memberid')"
        }
        #end
    ]
}

The output:

{
    "StreamName":"MemberApiAuditLog",
    "Records":[
        {
            "Data":"e3RpbWU9MjAxNy0wMS0wMVQxMTo0MzoyMSwgdHlwZT1JdGVtU2VsZWN0ZWQsIGFwcGxpY2F0aW9uPWlPUyBCdWlsZCAzNjU0fQ==",
            "PartitionKey":"my-member-id"
        }
        {
            "Data":"e3RpbWU9MjAxNy0wMS0wMToxMTo1NTozMiwgdHlwZT1JdGVtU2VsZWN0ZWQsIGFwcGxpY2F0aW9uPWlPUyBCdWlsZCAzNjU0fQ==",
            "PartitionKey":"my-member-id"
        }
    ]
}

And when you decode the first base64 string again, you should get this result:

{time=2017-01-01T11:43:21, type=ItemSelected, application=iOS Build 3654}

Please let me know if that worked for you.

Upvotes: -2

Related Questions