amazon-web-servicesamazon-dynamodbaws-appsyncvtl

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!


Solution

  • 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 :)