How to allow Optional Key in API Gateway mapping template - json

I have an API gateway that scans a DynamoDB table. I want to pass LastEvaluatedKey in my request body; if I pass a LastEvaluatedKey then the everything works and I get a response with the expected data - so I'm half way there.
But, of course, the first time I send a request to the API LastEvaluatedKey will not exist, so the ExclusiveStartKey in the mapping template that expects a LastEvaluatedKey must be optional. I've tried a few different ways to get this to be optional but nothing has worked so far. Here is what I have:
#set($hasName = $input.json('$.Name'))
{
"TableName": "MyTable",
#if($hasName && $hasName.length() != 0)
"ExclusiveStartKey": {
"Name": {
"S": $input.json('$.Name')
},
"Date": {
"S": $input.json('$.Date')
}
},#end
"FilterExpression": "begins_with(#dt, :tdt)",
"ExpressionAttributeNames": {
"#dt": "Date"
},
"ExpressionAttributeValues": {
":tdt": {
"S": "$input.params('date')"
}
}
}
As I say, the above works when I do pass a LastEvaluatedKey in my request body, but when I do not I get the error:
{
"__type": "com.amazon.coral.validate#ValidationException",
"message": "The provided starting key is invalid: One or more parameter values were invalid: An AttributeValue may not contain an empty string"
}
...it's still expected the LastEvaluatedKey
I've also tried wrapping Name and Date inside if #if but with no luck at all. I've taken inspiration from other answers such as: this and this, but no luck.

In my example cursor is the LastEvaluatedKey:
#set($hasCursor = $input.params('cursor') != "")
{
"TableName": "my-table"
#if($hasCursor) "ExclusiveStartKey":$util.base64Decode("$input.params('cursor')")
#end
}
It just checks if cursor is passed as a query param (like /my/api?cursor=myencodedlastevaluatedkey), and only adds ExclusiveStartKey to the request if it is.

If you know beforehand that both keys are string type, you can do:
#set($Name = $input.params('Name'))
#set($Date = $input.params('Date'))
{
#if($Name != '' && $Date != '')
"ExclusiveStartKey": {
"Name": {
"S": "$Name"
},
"Date": {
"S": "$Date"
}
},
#end
#if($Date != '')
"FilterExpression": "begins_with(#dt, :tdt)",
"ExpressionAttributeNames": {
"#dt": "Date"
},
"ExpressionAttributeValues": {
":tdt": {
"S": "$Date"
}
}
},
#end
"TableName": "MyTable"
}
This makes the filter optional, only if Date is passed as argument

Related

Replacement in a json array - Angular

I am trying to replace an object in my json web server array : If an object with a similar id is already in the json array.
This is my json array :
{
"history": [
{
"id": 4,
"SNS": "BockeSinoJutsu-SNS",
"title": "BockeSinoJutsu-title",
"DMC": "BockeSinoJutsu-DMC",
"date": "June 15 2022"
},
{
"id": 1,
"SNS": "Rasengan-SNS",
"title": "Rasengan-title",
"DMC": "Rasengan-DMC",
"date": "2022-06-18T17:43:59.708Z"
}
]
}
And this is the json file I am comparing it to :
{
"content":[
{
"id":1,
"SNS":"Rasengan-SNS",
"title":"Rasengan-title",
"DMC":"Rasengan-DMC"
},
{
"id":2,
"SNS":"Mangekyu-SNS",
"title":"Mangekyu-title",
"DMC":"Mangekyu-DMC"
},
{
"id":3,
"SNS":"Chidori-SNS",
"title":"Chidori-title",
"DMC":"Chidori-DMC"
}
]
}
This is what I have tried :
onAddHistory(history:History){
history.date = new Date();
console.log(history.SNS);
this.historyService.getHistory().subscribe(
(response:History[])=>{
this.ExistingHistory=response.filter(x => x.id === history.id);
console.log(this.ExistingHistory);
if(this.ExistingHistory.length !== 0){
this.onDeleteHistory(this.ExistingHistory.id);
this.historyService.addHistory(history).subscribe(
()=>{console.log("Success !");
this.Histories$=this.historyService.getHistory();},
()=>{console.log("error")}
);
}else{
this.historyService.addHistory(history).subscribe(
()=>{console.log("Success !");
this.Histories$=this.historyService.getHistory();},
()=>{console.log("error")}
);
}
}
);
}
But I get the following error, saying that it cannot read id of undefined :
The error basically says that ExistingHistory.id is undefined
JavaScript's Array.filter() returns a filtered array. You can't access this.ExistingHistory.id because this.ExistingHistory is an array, you would have to access it like so: this.ExistingHistory[0].id
If you want to get one value only then you should use Array.find():
this.ExistingHistory = response.find(x => x.id === history.id);
If there is a chance there is more than one duplicate, then you should use a .forEach loop:
this.ExistingHistory.forEach((x) => {
this.onDeleteHistory(x.id);
}
Do be warned however that you have a ton of nested subscriptions in that method, which is generally considered bad practice. I advise you to look into RXJS

Operator "missing" not working properly in JsonLogic

I am using JsonLogic to validate my input payload with the rules defined using JsonLogic. I am able to test the rules using "Play with it" tool and my rules work perfectly fine against my input data.
But when I run the same rules through my .net Core application by passing payload from Postman the rules always return the else condition even when it should the error from if condition.
{
"if": [
{
"missing": [
"ProposedProjectDetails.IsFreezone",
"ProposedProjectDetails.InterestedToLeaseFrom",
"ProposedProjectDetails.IndustryType",
"ProposedProjectDetails.OtherType",
"ProposedProjectDetails.ProjectDescription",
"ProposedProjectDetails.OutputofFacility",
"ProposedProjectDetails.ProductionCapacity",
"ProposedProjectDetails.ProductionCapacityVolume",
"ProposedProjectDetails.MainRawMaterials",
"ProposedProjectDetails.RawMaterialQuantity",
"ProposedProjectDetails.RawMaterialEstimatedCost",
"ProposedProjectDetails.RawMaterialEstimatedTotInvestment",
"ProposedProjectDetails.AnnualSalesRevenue",
"ProposedProjectDetails.ConstructionStartDate",
"ProposedProjectDetails.Skilledjobs",
"ProposedProjectDetails.TotalAccomodationRequired",
"ProposedProjectDetails.TotalWorkerSalary",
"ProposedProjectDetails.EBITDA",
"ProposedProjectDetails.PortCargoImports",
]
},
"Missing mandatory inputs",
"all good"
]
}
Sample input payload is
{
"companyId": "string",
"serviceCode": "IPA",
"serviceType": "string",
"serviceName": "string",
"crmApplicationId": "string",
"crmReferenceNumber": "string",
"portalReferenceNumber": "string",
"data": {
"proposedProjectDetails": {
"outputofFacility": 2,
"productionCapacity": 0,
"productionCapacityVolume": 0,
"others": "string",
"shiftsPerDay": 0
}
}
}
My .Net code which is evaluating this is
public ValidationResponse Validate(JObject validation, JObject data)
{
var evaluator = new JsonLogicEvaluator(EvaluateOperators.Default);
var result = evaluator.Apply(validation, data);
return new ValidationResponse
{
IsValid = (string.Equals("All Fine", result.ToString(), StringComparison.OrdinalIgnoreCase)),
Message = result
};
}
When I run above code with JsonRules and above Payload, I always get all good in the response. But since I am missing required data in payload, it should get the error Missing mandatory inputs which I do get in JsonLogic "Play with it" tool.
Try keeping the names as json mapping fields camel case once like below
"if": [
{
"missing": [
"proposedProjectDetails.isFreezone",
"proposedProjectDetails.interestedToLeaseFrom",
]
},
"Missing mandatory inputs",
"all good"
]
}

Not able to fetch the value of a key from JSON data

I am trying to fetch value if "id" from JSON response I got from a POST request.
{
"callId": "87e90efd-eefb-456a-b77e-9cce2ed6e837",
"commandId": "NONE",
"content": [
{
"scenarioId": "SCENARIO-1",
"Channel": "Channel1-1",
"data": {
"section": {
"class": {
"repository": [
{
"export": "export-1",
"modules": "module-1",
"index": "23",
"period": {
"axis": {
"new_channel": "channel-1.1"
},
"points": [
{
"id": "6a5474cf-1a24-4e28-b9c7-6b570443df9c",
"duration": "150",
"v": 1.01,
"isNegligible": false
}
]
}
}
]
}
}
}
}
]
}
I am able to display the entire response json and am also able to get the value of "callId" using below code. Getting error at last line:
Cannot read property '0' of undefined
Code snippet:
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
let responseData = JSON.stringify(body);
//Display the entire response
console.log(responseData);
//Display the callId
console.log(body['callId']);
//Getting error here
console.log(body.content[0].repository[0].points[0].id);
}
}
Any solution to get value of "id" ?
Right now you are trying to log body.content[0].repository[0].points[0].id).
If you look at it carefully the repository[0] is an object and it has no immediate child points.
So repository[0].points would evaluate to undefined and by specifying repository[0].points[0], you are trying to access property 0 of undefined as the error states.
The correct way of accessing id would be as follows :
body.content[0].data.section.class.repository[0].period.points[0].id
If you have confusion regarding parsing JSON try breaking it down by consoling body and then by expanding it in the console or in JSONeditor
PS: It is also recommended that you check at each level if the value exists before trying to access a deeper child elements, since in some cases your body may not contain one of the values, say content for example. In that case trying to access body.content[0] will cause an error. So it is recommended to do checks at each level like follows
if(body){
if(body.content){
if(body.content[0]){
/* and so on*/
}
}
}
Try with
console.log(body.content[0].data.section.class.repository[0].period.points[0].id)

Assign Data from child to parent in json object

I had a object array containing items
"0: Object
Entity: "Customer"
Id: 157
Message: "testMessage1"
Property: Object
Name: "LastName"
Rules: "NotEmpty""
Here, How could I pass Name value to Property
Name is act as key within in Property object.
how could I Discard the Name and assign the value of Name i.e. (Last Name) to Property
This is what I have right now:
[
{
"Entity":"Customer",
"Property": {"Name": "Email", "Type": "System.String" },
"Rules":"NotEmpty",
"Message":"ssdsdsds",
"Id":157,
"ValueToCompare": null,
}
]
Here, I need to assign Name value (i.e : Email) to Property Directly (it would be like this :-- "Property": "Email")
assuming this is your json
[
{
"0": {
"Entity": "Customer",
"Id": 157,
"Message": "testMessage1"
},
"Property": {
"Name": "LastName",
"Rules": "NotEmpty"
}
}
]
your original json contain in
originaljson
and transform json contain in
transformjson
JSONArray originaljson;
JSONArray transformjson=originaljson;
for(int i=0;i<originaljson.length();i++)
{
JSONObject mainJson=originaljson.getJSONObject(i);
String name=mainJson.getJSONObject("Property").getString("Name");
//mainJson.remove("Property");
JSONObject mainJsonTransform=transformjson.getJSONObject(i);
mainJsonTransform.remove("Property");
mainJsonTransform.put("Property",name);
}
now your transformjson contain the desired json
Thank you guys for your interest with this question.
At last I have write down the proper solution
My own solution to solve this problem is..
In javascript :
function addProp(obj, propName) {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
if (p == propName) {
if (obj[p].Name == null) {
obj[p] = obj[p];
}
else
{
obj[p] = obj[p].Name;
}
} else if (typeof obj[p] == 'object') {
addProp(obj[p], propName);
}
}
}
return obj;
}
Calling this function :
addProp(data, 'Property')
This work properly now

How to return a subcollection (or object) in json without including all attributes

I am using mongoose as JSON Schema and node.js with it. Need not say, I am new to both. I have been struggling through the day to get this thing work for me but couldn't. Finally, the only solution was to get help from some real nice people out here.
Here is my schema definition -
UserName = {
"properties": {
userURL: {
"description": "URL of this resource",
"type": "string"
},
userName : {
"description": "UserName",
"type": "string",
"required": true
},
}
}
When I make a get call to it, it returns the response in following format -
[
{
"_id": "54c5ede55c82c4bd6abee50a",
"__v": 0,
"properties": {
"userURL": "http://localhost:3000/54c1d6ae441ae900151a6520",
"userName ": "testUser"
}
}
]
Now my requirement is to return the response in following format -
[
{
"_id": "54c5ede55c82c4bd6abee50a",
"userURL": "http://localhost:3000/54c1d6ae441ae900151a6520",
"userName ": "testUser"
}
]
i.e without version and properties tags. I am able to get away with version using following code but properties seems to be tricky thing -
.get(function(request, response) {
UserSchemaModel.find().select('properties.userURL properties.userName').exec (function (err, resObj) {
if (err)
response.send(err);
else{
response.json(resObj);
}
});
});
But it still has properties field :( -
[
{
"_id": "54c5ede55c82c4bd6abee50a",
"properties": {
"userURL": "http://localhost:3000/54c1d6ae441ae900151a6520",
"userName ": "testUser"
}
}
]
I did some google around select as, alias name in select,population in mongoose but no luck.
Kindly suggest. With best Regards.
Just make a new object
response.json(
{
"_id": resObj["_id"],
"userURL": resObj["properties"]["userUrl"],
"userName": resObj["properties"]["userName"]
}
);
Update: Since resObj is an array (as per your comment), you can use Array.prototype.map() to transform them into the right format like so:
response.json( resObj.map(function(o){
return {
"_id": o["_id"],
"userURL": o["properties"]["userUrl"],
"userName": o["properties"]["userName"]
};
})
);
This will return a list of transformed objects that then get passed into the response.json() method.