Add or Update Property on JSON object with Mapping Template (AWS API Gateway) - aws-api-gateway

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?

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

Update only the given column value with appsync api and datasource as posgresql

I have created appsync api with postgresql as datasource. Now it's very straight to create , update and delete any record with graphql. But i want something like, whenever any update takes places , i can update value of that particular column only. Eg
lets we have user table with 3 fields:
user_id
name
city
now when we update city for user than only city should update:
mutation update{
updateUser(input:{user_id:"xxxxx",city:"xyz"}){
user_id
name
city
}}
user update input:
input updateUserInput{
user_id!
name
city
}
Is there any way to do this in vtx template or we have to use lambda as datasource and then do this.
I figured it out how we can achieve it:
you can do like this:
#set ($updates = "")
#foreach( $item in $ctx.args.input.keySet())
#if($item)
#set ($updates = "$updates, $item = '$ctx.args.input.get($item)'")
#end
#end
--------used cognito as authentication , so user id will come in indentity
#set($user_id = ($ctx.identity.username))
#set($updates = "$updates, updated_at = '$util.time.nowFormatted('yyyy-MM-dd HH:mm:ssZ')'")
{
"version": "2018-05-29",
"statements": [
$util.toJson("update public.tableName SET $updates.substring(1) WHERE user_id = '$user_id'"),
$util.toJson("select * from public.tableName WHERE user_id = '$user_id'")
]
}
I hope it will help someone.

Web Services call - core_group_create_groups - Unexpected keys (courseid) detected in parameter array

I'm having an issue with a specific Rest webservice call :
Method: core_group_create_groups
Is throwing the following error:
Unexpected keys (courseid) detected in parameter array.
I'm passing in the exact properties defined in the documentation:
_ //List of group object. A group has a courseid, a name, a description and an enrolment key.
list of (
object {
courseid int //id of course
name string //multilang compatible name, course unique
description string //group description text
descriptionformat int Default to "1" //description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN)
enrolmentkey string Optional //group enrol secret phrase
idnumber string Optional //id number
}
)_
I'm using Moodle 3.1+ (Build: 20160623)
Any ideas why it doesn't like courseid in the request even though its a valid parameter?
having problems here with Moodle documentation too.
parameters marked as optional in docs actually are required.
example:
in the method 'core_role_assign_roles' you MUST pass 'contextlevel' and 'instanceid', the doc say is optional.
I just used the 'core_group_create_groups' method and it worked fine. this time the docs were correct passed 3 params: courseid / name / description.
used like:
"groups[0][courseid]=2&groups[0][name]=grupo2&groups[0][description]=desc grupo2"
maybe double check if the code you are passing in courseid a) exists; b) is really a course id.
hope it helps,
rodrigo
You have to call the webservice using the "groups" key to make it works correctly (i.e. this code works for me in PHP):
`$this->callWSFunction(
'core_group_create_groups',[
groups =>[
0 =>
[
'courseid' => $id,
'name' => $groupname,
'description' => $groupdescription
]
]
]
);`

Moped: get id after inserting

When I use mongo-ruby-driver and I insert new document it returns generated '_id':
db = MongoClient.new('127.0.0.1', '27017').db('ruby-mongo-examples')
id = db['test'].insert({name: 'example'})
# BSON::ObjectId('54f88b01ab8bae12b2000001')
I'm trying to get the '_id' of a document after doing an insertion using Moped:
db = Moped::Session.new(['127.0.0.1:27017'])
db.use('ruby-mongo-examples')
id = db['coll'].insert({name: 'example'})
# {"connectionId"=>15, "n"=>0, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
How I get the id using Moped?
Update:
I also try use safe mode but it doesn't work:
db = Moped::Session.new(['127.0.0.1:27017'])
db.use('ruby-mongo-examples')
db.with(safe: true) do |safe|
id = safe['coll'].insert({name: 'example'})
# {"connectionId"=>5, "n"=>0, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
end
After inserting/saving, the returned object will have a property inserted_id which is a BSON::ObjectId:
# I'm using insert_one
result = safe['coll'].insert_one({name: 'example'})
result.methods.sort # see list of methods/properties
result.inserted_id
result.inserted_id.to_s # convert to string
From this issue:
It would be nice, but unfortunately Mongo doesn't give us anything
back when inserting (since it's fire and forget), and when in safe
mode it still doesn't give the id back if it generated it on the
server. So there really isn't any possible way for us to do this
unless it was a core feature in MongoDB.
Your best bet would be to generate the id before inserting the document:
document = { _id: Moped::BSON::ObjectId.new, name: "example" }
id = document[:_id]

How to include the 'id' (field) of an entity in the response after a POST (create) event in Apigility?

Given a json string:
POST localhost:8080/person
{
f_name : 'Juan',
l_name : 'Dela Cruz'
}
we would usually return a boolean true value upon success so that apigility would return/render something like this:
200 Ok
{
f_name : 'Juan',
l_name : 'Dela Cruz'
}
How can I also include the id of the newly created entity in the resulting response? It may look something like this:
200 Ok
{
id : 1,
f_name : 'Juan',
l_name : 'Dela Cruz'
}
Any help/lead is highly appreciated.
I am including my own answer here, but I think this is not the best possible way.
I have discovered that you can also return an array from the create (POST) method of the resource with the 'id' field taken from the lastInsertValue property of an db adapter object and added into the array.
$insert['f_name'] = 'Juan';
$insert['l_name'] = 'Dela Cruz';
$table = new TableGateway('person', $adapter);
$table->insert($insert);
$insert['id'] = $table->lastInsertValue;
return $insert;
I hope there are still other ways to do this.
Apigility does indeed return the object you send. If you want to get a different result you can construct it yourself and return it as
javiniar.leonard also pointed out.
Important is that you do not try to json_encode it but let Apigility handle that.
I use the API to send items created in an app with a local id, and return the local id and web_id to allow for synchronization on multiple devices.

Updating an array of objects fields in crate

I created a table with following syntax:
create table poll(poll_id string primary key,
poll_type_id integer,
poll_rating array(object as (rating_id integer,fk_user_id string, israted_image1 integer, israted_image2 integer, updatedDate timestamp, createdDate timestamp )),
poll_question string,
poll_image1 string,
poll_image2 string
)
And I inserted a record without "poll_rating" field which is actually an array of objects fields.
Now when I try to update a poll_rating with the following commands:
update poll set poll_rating = [{"rating_id":1,"fk_user_id":-1,"israted_image1":1,"israted_image2":0,"createddate":1400067339.0496}] where poll_id = "f748771d7c2e4616b1865f37b7913707";
I'm getting an error message like this:
"SQLParseException[line 1:31: no viable alternative at input '[']; nested: ParsingException[line 1:31: no viable alternative at input '[']; nested: NoViableAltException;"
Can anyone tell me why I get this error when I try to update the array of objects fields.
Defining arrays and objects directly in SQL statement is currently not supported by our SQL parser, please use parameter substitution using placeholders instead as described here:
https://crate.io/docs/current/sql/rest.html
Example using curl is as below:
curl -sSXPOST '127.0.0.1:4200/_sql?pretty' -d#- <<- EOF
{"stmt": "update poll set poll_rating = ? where poll_id = ?",
"args": [ [{"rating_id":1,"fk_user_id":-1,"israted_image1":1,"israted_image2":0,"createddate":1400067339.0496}], "f748771d7c2e4616b1865f37b7913707" ]
}
EOF