Body Mapping template AWS lambda API - amazon-web-services

I need to pass 2 arrays and 2 vars. with API to LAmbda function
I get everytime this:
{"message": "Could not parse request body into json: Unexpected character (\',\' (code 44)): expected a valid value (number, String, array, object, \'true\', \'false\' or \'null\')\n at [Source: [B#5a648099; line: 5, column: 11]"}
My template mapping:
{
"items":
[
#foreach($elem in $input.params('items').split(','))
{
"ids": $elem.ids,
"contents": $elem.contents
}#if($foreach.hasNext),#end
#end
],
"QueryID": $input.params('QueryID'),
"nR": $input.params('nR')
}

Try quoting your values:
{
"items": [
#foreach($elem in $input.params('items').split(','))
{
"ids": "$elem.ids",
"contents": "$elem.contents"
}#if($foreach.hasNext),#end
#end
],
"QueryID": "$input.params('QueryID')",
"nR": "$input.params('nR')"
}

This looks like you are trying to pass items in the "params" field. If you are passing in items, QueryID, and nR every time, just put $input.json('$') (only that, remove everything else, even the surrounding {}). If that doesn't work, refer to #dave-maple's answer

Related

Django loop through json object

How to loop through a JSON object in Django template?
JSON:
"data": {
"node-A": {
"test1A": "val1A",
"test2A": "val2A",
"progress": {
"conf": "conf123A"
"loc": "loc123A"
},
"test3A": "val3A"
},
"node-B": {
"test1B": "val1B",
"test2B": "val2B",
"progress": {
"conf": "conf123B"
"loc": "loc123B"
},
"test3B": "val3B"
}
}
I am having trouble accessing the nested values "conf" and "lock" inside "progress". How can I access them in Django template if the data is passed as context i.e. return (request, 'monitor.html', {"data_context": json_data['data']})?
they way you have it set up, your data is in a dictionary called 'data_context'. To access what you need in the template it would be {{data_context.test1A}}.
to not have to use 'data_context.' try this instead,
return (request, 'monitor.html', json_data['data'].to_dict())
Dictionary lookup, attribute lookup and list-index lookups are implemented with a dot notation:
{{ my_dict.key.key_nested }}
As the JSON format behaves like a dictionary in Python, the data stored with the specified keys conf and loc should be accessible with the python notation for dictionaries. Since the provided JSON can be seen as a nested dictionary, you need to "concat" the keys respectively to get your desired data.
Your return statement returns a dictionary which I will call ret so the structure should be:
{"data_context": {
"node-A": {
"test1": "val1A",
"test2": "val2A",
"progress": {
"conf": "conf123A",
"loc": "loc123A"
},
"test3": "val3A"
},
"node-B": {
"test1B": "val1B",
"test2B": "val2B",
"progress": {
"conf": "conf123B",
"loc": "loc123B"
},
"test3": "val3B"
}
}
}
Therefor to access conf and loc:
ret["data_context"]["node-A"]["progress"]["conf"]
will get you the value stored at conf in node-A

Secondary Index not working for Database using #key

I should get the DynamoDb id for Justin. The call doesn't seem to fail. If i console.log(returned) i get an [object Object]. When i try to get to the returned.data.getIdFromUserName.id or returned.data.getIdFromUserName.email (anything else in the table) i get undefined. What am i missing?
Returned data:
{
"data": {
"getIdFromUserName": {
"items": [
{
"id": "3a5a2ks4-f137-41e2-a604-594e0c52a298",
"userName": "Justin",
"firstname": "null",
"weblink": "#JustinTimberlake",
"email": "iuiubiwewe#hotmail.com",
"mobileNum": "+0123456789",
"profilePicURI": "null",
"listOfVideosSeen": null,
"userDescription": "I wanna rock your body, please stay",
"isBlocked": false,
"GridPairs": null
}
],
"nextToken": null
}
}
}
I'd suggest getting a better idea of what console.log(returned) is printing.
Try console.log(JSON.stringify(returned, null, 2)) to inspect what is being returned.
EDIT: The data you're working with looks like this:
{
"data": {
"getIdFromUserName": {
"items": [
{
"id": "3a5a2ks4-f137-41e2-a604-594e0c52a298",
"userName": "Justin",
"firstname": "null",
"weblink": "#JustinTimberlake",
"email": "iuiubiwewe#hotmail.com",
"mobileNum": "+0123456789",
"profilePicURI": "null",
"listOfVideosSeen": null,
"userDescription": "I wanna rock your body, please stay",
"isBlocked": false,
"GridPairs": null
}
],
"nextToken": null
}
}
}
Pay close attention to the structure of that response. Both data and getIdFromUserName are maps. The content of data.getIdFromUserName is an array named items. Therefore, data.getIdFromUserName.items is an array containing the results of your query. You'll need to iterate over that array to get the data you are looking for.
For example, data.getIdFromUserName.items[0].id would be 3a5a2ks4-f137-41e2-a604-594e0c52a298
To access the email it would be data.getIdFromUserName.items[0].email.

Amazon EventBridge: Match an object inside of an array

I've stuck the problem with defining a rule for matching my events.
Googled, tested.
Let's say, we've the following event which contains the object user in the array events:
{
"version": "0",
"...": "...",
"detail": {
"events": [
{
"user": {
"id": "5efdee60b48e7c1836078290"
}
}
]
}
}
Is there any way to match the user.id in an EventBus rule?
I've already tried to use the following rule which is not valid:
{
"detail": {
"events": [
{
"user": {
"id": [
"5efdee60b48e7c1836078290"
]
}
}
]
}
}
then,
{
"detail": {
"events[0]": {
"user": {
"id": [
"5efdee60b48e7c1836078290"
]
}
}
}
}
also no effect.
I don't want to give up, but I'm tired with it ;)
This pattern should work to match this event:
{
"detail": {
"events": {
"user": {
"id": [
"5efdee60b48e7c1836078290"
]
}
}
}
}
Today, EventBridge only supports matching simple values (string, integer, boolean, null) with an array. You can read more in the service documentation.
I did some playing around with your example but I can't make it work. Based on reading the Arrays in EventBridge Event Patterns I have to conclude that matching inside arrays with complex values is not possible.
The quote that seems to confirm this is "If the value in the event is an array, then the pattern matches if the intersection of the pattern array and the event array is non-empty."
And from the Event Patterns page "Match values are always in arrays." So if your pattern is an array and the value in the event is also an array (this is the example you gave), a "set" based intersection test is performed. Your pattern would have to match the entire array entry, not just a single field like you have in the example.

How to resolve parent to child relationship with AppSync

I have schema looking like below
type Post {
id: ID!
creator: String!
createdAt: String!
like: Int!
dislike: Int!
frozen: Boolean!
revisions:[PostRevision!]
}
type PostRevision {
id: ID!
post: Post!
content: String!
author: String!
createdAt: String!
}
type Mutation {
createPost(postInput: CreatePostInput!): Post
}
I would like to be able to batch insert Post and PostRevision at the same time when i run createPost mutation; however, VTL is giving me a much of hard time.
I have tried below
## Variable Declarations
#set($postId = $util.autoId())
#set($postList = [])
#set($postRevisionList = [])
#set($post = {})
#set($revision = {})
## Initialize Post object
$util.qr($post.put("creator", $ctx.args.postInput.author))
$util.qr($post.put("id", $postId))
$util.qr($post.put("createdAt", $util.time.nowEpochMilliSeconds()))
$util.qr($post.put("like", 0))
$util.qr($post.put("dislike", 0))
$util.qr($post.put("frozen", false))
## Initialize PostRevision object
$util.qr($revision.put("id", $util.autoId()))
$util.qr($revision.put("author", $ctx.args.postInput.author))
$util.qr($revision.put("post", $postId))
$util.qr($revision.put("content", $ctx.args.postInput.content))
$util.qr($revision.put("createdAt", $util.time.nowEpochMilliSeconds()))
## Listify objects
$postList.add($post)
$postRevisionList.add($revision)
{
"version" : "2018-05-29",
"operation" : "BatchPutItem",
"tables" : {
"WHISPR_DEV_PostTable": $util.toJson($postList),
"WHISPR_DEV_PostRevisionTable": $util.toJson($postRevisionList)
}
}
So basically I am reconstructing the document in the resolver of createPost so that I can add Post then also add ID of the post to postReivision However when I run below code
mutation insertPost{
createPost(postInput:{
creator:"name"
content:"value"
}){
id
}
}
I get following error
{
"data": {
"createPost": null
},
"errors": [
{
"path": [
"createPost"
],
"data": null,
"errorType": "MappingTemplate",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Expected JSON object but got BOOLEAN instead."
}
]
}
What am I doing wrong?
I know it would be easier to resolve with lambda function but I do not want to double up the cost for no reason. Any help would be greatly appreciated. Thanks!
If anyone still needs the answer for this (this question is still the #1 google hit for the mentioned error message):
The problem is the return value of the add() method, which returns a boolean value.
To fix this, just wrap the add() methods into $util.qr, as you are already doing for the put() methods:
$util.qr(($postList.add($post))
$util.qr(($postRevisionList.add($revision))
It looks like you are missing a call to $util.dynamodb.toDynamoDBJson which is causing AppSync to try to put plain JSON objects into DynamoDB when DynamoDB requires a DynamoDB specific input structure where each attribute instead of being a plain string like "hello world!" is an object { "S": "hello world!" }. The $util.dynamodb.toDynamoDBJson helper handles this for you for convenience. Can you please try adding the toDynamoDBJson() to these lines:
## Listify objects
$postList.add($util.dynamodb.toDynamoDBJson($post))
$postRevisionList.add($util.dynamodb.toDynamoDBJson($revision))
Hope this helps :)

"type mismatch error, expected type LIST" for querying a one-to-many relationship in AppSync

The schema:
type User {
id: ID!
createdCurricula: [Curriculum]
}
type Curriculum {
id: ID!
title: String!
creator: User!
}
The resolver to query all curricula of a given user:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
## Provide a query expression. **
"expression": "userId = :userId",
"expressionValues" : {
":userId" : {
"S" : "${context.source.id}"
}
}
},
"index": "userIdIndex",
"limit": #if(${context.arguments.limit}) ${context.arguments.limit} #else 20 #end,
"nextToken": #if(${context.arguments.nextToken}) "${context.arguments.nextToken}" #else null #end
}
The response map:
{
"items": $util.toJson($context.result.items),
"nextToken": #if(${context.result.nextToken}) "${context.result.nextToken}" #else null #end
}
The query:
query {
getUser(id: "0b6af629-6009-4f4d-a52f-67aef7b42f43") {
id
createdCurricula {
title
}
}
}
The error:
{
"data": {
"getUser": {
"id": "0b6af629-6009-4f4d-a52f-67aef7b42f43",
"createdCurricula": null
}
},
"errors": [
{
"path": [
"getUser",
"createdCurricula"
],
"locations": null,
"message": "Can't resolve value (/getUser/createdCurricula) : type mismatch error, expected type LIST"
}
]
}
The CurriculumTable has a global secondary index titled userIdIndex, which has userId as the partition key.
If I change the response map to this:
$util.toJson($context.result.items)
The output is the following:
{
"data": {
"getUser": {
"id": "0b6af629-6009-4f4d-a52f-67aef7b42f43",
"createdCurricula": null
}
},
"errors": [
{
"path": [
"getUser",
"createdCurricula"
],
"errorType": "MappingTemplate",
"locations": [
{
"line": 4,
"column": 5
}
],
"message": "Unable to convert \n{\n [{\"id\":\"87897987\",\"title\":\"Test Curriculum\",\"userId\":\"0b6af629-6009-4f4d-a52f-67aef7b42f43\"}],\n} to class java.lang.Object."
}
]
}
If I take that string and run it through a console.log in my frontend app, I get:
{
[{"id":"2","userId":"0b6af629-6009-4f4d-a52f-67aef7b42f43"},{"id":"1","userId":"0b6af629-6009-4f4d-a52f-67aef7b42f43"}]
}
That's clearly an object. How do I make it... not an object, so that AppSync properly reads it as a list?
SOLUTION
My response map had a set of curly braces around it. I'm pretty sure that was placed there in the generator by Amazon. Removing them fixed it.
I think I'm not seeing the complete view of your schema, I was expecting something like:
schema {
query: Query
}
Where Query is RootQuery, in fact you didn't share us your Query definition. Assuming you have the right Query definition. The main problem is in your response template.
> "items": $util.toJson($context.result.items)
This means that you are passing a collection named: *"items"* to Graphql query engine. And you are referring this collection as "createdCurricula". So solve this issue your response-mapping-template is the right place to fix. How? just replace the above line with the following.
"createdCurricula": $util.toJson($context.result.items),
Please the main thing to note here is, the mapping template is a bridge between your datasources and qraphql, feel free to make any computation, or name mapping but don't forget that object names in that response json are the one should match in schema/query definition.
Thanks.
Musema
change to result type to $util.toJson($ctx.result.data.posts)
The exception msg says that it expected a type list.
Looking at:
{
[{"id":"2","userId":"0b6af629-6009-4f4d-a52f-67aef7b42f43"},{"id":"1","userId":"0b6af629-6009-4f4d-a52f-67aef7b42f43"}]
}
I don't see that createdCurricula is a LIST.
What is currently in DDB is:
"id": "0b6af629-6009-4f4d-a52f-67aef7b42f43",
"createdCurricula": null