6

I'm trying to batch put a number of items to DynamoDB using AppSync. When I call the resolver it throws no errors but nothing is saved to the database.

Schema

type BoxScore @model {
  id: ID!
  userId: String!
  gameVariant: String!
  complete: Boolean!
  failFact: BoxScoreFact @connection
  totalCorrect: Int!
}

type BoxScoreFact @model {
  id: ID!
  left: Int!
  right: Int!
  gameVariant: String!
  timestamp: Int!
  correct: Boolean!
}

input BatchAddCreateBoxScoreFactInput {
  id: ID
  left: Int!
  right: Int!
  gameVariant: String!
  timestamp: Int!
  correct: Boolean!
  boxScoreFactBoxScoreId: ID!
}

IAM Role:

        "Effect": "Allow",
        "Action": [
            "dynamodb:DeleteItem",
            "dynamodb:GetItem",
            "dynamodb:PutItem",
            "dynamodb:Query",
            "dynamodb:Scan",
            "dynamodb:UpdateItem",
            "dynamodb:BatchGetItem",
            "dynamodb:BatchWriteItem"
        ],

Resolver:

#set($factsdata = [])
#foreach($item in ${ctx.args.facts})
    $util.qr($factsdata.add($util.dynamodb.toMapValues($item)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        "TABLENAME": $utils.toJson($factsdata)
    }
}

Call from AppSync playground:

enter image description here

Response mapping template:

  #if($ctx.error)
      ## Append a GraphQL error for that field in the GraphQL response
      $utils.error($ctx.error.message, $ctx.error.message)
  #end

  {
      "boxScoreFacts": $util.toJson({"res": "no error", "ctx": $ctx}),
  }

Output template from Function test run:

enter image description here

DynamoDB Table

enter image description here

Where TABLENAME is set equal to the DynamoDB table name that is displayed in the DDB console. So something like BoxScoreFact-woieieie99392-prod.

The table is always empty and the response is null. This is lifted almost straight out of the example from the docs. Also, I should note, that putting one item using the normal create graphql function does put an item to the intended table.

What am I missing here?

Max Phillips
  • 6,991
  • 9
  • 44
  • 71
  • Could you provide your response mapping template? – Neill Aug 26 '19 at 08:55
  • @Neill added. If the response mapping template is invalid would it prevent the put from happening entirely, i.e. no save to the table? – Max Phillips Aug 26 '19 at 15:55
  • You can try and enable logging for AppSync and see if there is anything interesting in the logs. Also what are the IAM permissions for your role? – Erez Aug 26 '19 at 17:05
  • @Phil, not really, but you may not be seeing the error returning from DynamoDB, Could you try to raise an error instead of appending the error? – Neill Aug 27 '19 at 08:30
  • @Neill The screen shot that shows the $ctx output from the resolver template is truncated, apparently not copiable, has error: null, and outError: []. So it doesn't seem like anything is going wrong. Also, I should note, that putting one item using the normal create graphql function does put an item to the intended table. – Max Phillips Aug 27 '19 at 13:22
  • Very weird this problem. Could you change your mutation return to string `batchAddBoxScoreFacts(facts: [BatchAddCreateBoxScoreFactInput]): String` and the response mapping to `$util.toJson($ctx)`? This way we'll have a full stringify response and get tips to solve your problem. You'll receive something like this: `"{arguments={facts=[{boxScoreFactBoxScoreId=123, gameVariant=0}]}, identity=null, source=null, result={data={Test=[{gameVariant=0, boxScoreFactBoxScoreId=123}]}, unprocessedItems={Test=[]}}, request={...}, error=null, prev=null, stash={}, outErrors=[]}"` – Pedro Arantes Aug 28 '19 at 01:42
  • can we see your dynamodb schema? – kkesley Aug 28 '19 at 03:55
  • @kkesley did you mean the graphql schema? added – Max Phillips Aug 28 '19 at 13:23
  • @PhilAndrews I meant the dynamodb schema itself (has & range key). The graphql schema is a good information as well. While you're at it, can you give us `BatchAddCreateBoxScoreFactInput` schema as well? – kkesley Aug 28 '19 at 22:49

3 Answers3

0

The lambda function of Appsync is called over the Serverless Appsync plugin and within this role the BatchWriteItem is missing in older versions. Within your package.json file try changing the plugin version to the latest or the GitHub version in which this problem is fixed.

This should fix it:

"devDependencies": {
   ....
   "serverless-appsync-plugin": "^1.1.0"
   ....
}

or

"devDependencies": {
   ....
   "serverless-appsync-plugin": "https://github.com/sid88in/serverless-appsync-plugin.git#e33b5cfd"
   ....
}
benra
  • 386
  • 1
  • 4
  • 18
  • It shouldn't be necessary to use an additional package to get this to work – Max Phillips Aug 28 '19 at 13:16
  • Ok, I had exactly the same problem as you did so I was assuming you would be using this package. This was my solution which took forever to find. – benra Aug 29 '19 at 08:16
0

It doesn't look like the mandatory id is being passed among your variables. You can try setting it automatically in your resolver:

#set($factsdata = [])
#foreach($item in ${ctx.args.facts})
    $util.qr($item.put("id", $util.defaultIfNullOrBlank($item.id, $util.autoId())))
    $util.qr($factsdata.add($util.dynamodb.toMapValues($item)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        "TABLENAME": $utils.toJson($factsdata)
    }
}
0

The solution for me was to include the batch permissions in the IAM role "dynamodb:BatchGetItem" and "dynamodb:BatchWriteItem". Seems that this operations aren't included by default.

Final json policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem",
                "dynamodb:BatchGetItem",
                "dynamodb:BatchWriteItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:<region>:<account_id>:table/<TableName>",
                "arn:aws:dynamodb:<region>:<account_id>:table/<TableName>/*"
            ]
        }
    ]
}
William Ardila
  • 1,049
  • 13
  • 22