Add or Update Property on JSON object with Mapping Template (AWS API Gateway)

Viewed 1236

In my AWS APIGW Rest API, I'm trying to add and/or update a property on the request body (JSON) that is submitted. Every example I could find deals with constructing a new JSON object, not updating the existing one.

In the Integration Request Mapping Template, my incoming data body looks like this. If it's a new object getting posted, it won't have an ID. If it's an existing object, it will have an ID. The goal here is to ALWAYS ensure it has an ID by either getting the existing one and setting it back to the JSON object or adding a new one.

// New object getting added, No ID
{
    "first_name" : "Toby",
    "last_name" : "Keith"
}


// Existing object getting updated, Has ID
{
    "id" : "abcdef"
    "first_name" : "Toby",
    "last_name" : "Keith"
}

My Integration Request Mapping Template looks like this:

## Do we have an existing id? (this is correctly pulling the existing ID)
#set( $id = $input.path('$.id') )
## If no ID, create one using the RequestID.  (This is also working)
#if ( $id == "" ) #set( $id = $context.requestId ) #end
## Get the entire json request string as json object
#set( $json_obj = $input.json('$') )
## Overwrite the ID on the json body to make sure we always have one
## [HERE IS THE PROBLEM]
## This isn't setting the id back on the $json_obj
#set( $input.path('$.id') = "$id" )
{
    "data": "$util.escapeJavaScript($json_obj).replaceAll("\\'","'")"
}

I want the value for "data" above to be a JSON string which includes an id as well as first_name and last_name.

I've tried numerous variations on setting the property, but no luck as of yet. None of these are working.

// Tries to update the JSON string I think, not the $json_obj
#set( $input.path('$.id') = "$id" )
// These cause error (because of quotes?)
#set( "$json_obj.id" = "BBBB" )
#set( '$json_obj.id' = "CCCC" )
// Doesn't work
#set( $input.path("$json_obj.id") = "DDDD" )
#set( $json_obj.id = "EEEE" )

As a plan B, I could break the $json_obj into key/value pairs and loop over them checking for an ID and either add or update it. Essentially building out a new JSON object, but that seems like the less preferable way than setting the property directly.

Does anyone know how to add/update a property on a JSON object with mapping templates?

1 Answers

I found the issue. This line is NOT converting the body payload into a JSON object like I thought. After more careful reading of the documentation, I see that it examines a JSON path expression and returns a matching JSON string.

#set( $json_obj = $input.json('$') )

To convert it into an object, I needed this syntax:

#set( $json_obj = $util.parseJson($input.json('$')) )

The corrected mapping template now looks like this

## Do we have an existing id? (this is correctly pulling the existing ID)
#set( $id = $input.path('$.id') )
## If no ID, create one using the RequestID.  (This is also working)
#if ( $id == "" ) #set( $id = $context.requestId ) #end
## Get the entire json request string as json object
#set( $json_obj = $util.parseJson($input.json('$')) )
## Overwrite the ID on the json body to make sure we always have one
## This isn't setting the id back on the $json_obj
#set( $input.path('$.id') = "$id" )
{
    "data": "$util.escapeJavaScript($json_obj).replaceAll("\\'","'")"
}

However, this leads to a secondary problem of now converting the JSON object back to a properly formatted JSON String. If I print out the JSON object, I get unquoted strings for some reason.

# Print out $json_obj 
$page_obj

Results in

{first_name=Toby, last_name=Keith}

I'll open a new question for that issue if I am unable to solve it.

2021/11/30 UPDATE:

It's been a while since I worked on this project but for completeness, I ended up being able to set the ID on the input before pulling the object into JSON.

## Pull the existing ID
#set( $id = $input.path('$').id )
## If empty, assign new ID
#if ( $id == "" ) #set ( $id = $context.requestId ) #end
## Assign the ID to the input
#set( $input.path('$').id = $id )
## Now pull the data out as an object
#set( $data = $input.json('$') )

The real difference is path('$.id') is now path('$').id to properly assign the id to the input before extracting the input into a JSON object.

Related