2
votes

I've been following the tutorial for batch operations: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-batch.html#multi-table-batch

When I tried to do a multi-table batch, I get a null response even though the objects are successfully submitted to dynamodb.

This is my mutation:

mutation sendReadings {
  recordReadings(
    tempReadings: [
      {sensorId: 1, value: 85.5, timestamp: "2018-02-01T17:21:05.000+08:00"},
      {sensorId: 2, value: 85.7, timestamp: "2018-02-01T17:21:06.000+08:00"},
      {sensorId: 3, value: 85.8, timestamp: "2018-02-01T17:21:07.000+08:00"},
      {sensorId: 4, value: 84.2, timestamp: "2018-02-01T17:21:08.000+08:00"},
      {sensorId: 5, value: 81.5, timestamp: "2018-02-01T17:21:09.000+08:00"}
    ]
    locReadings: [
      {sensorId: 1, lat: 47.615063, long: -122.333551, timestamp: "2018-02-01T17:21:05.000+08:00"},
      {sensorId: 2, lat: 47.615163, long: -122.333552, timestamp: "2018-02-01T17:21:06.000+08:00"}
      {sensorId: 3, lat: 47.615263, long: -122.333553, timestamp: "2018-02-01T17:21:07.000+08:00"}
      {sensorId: 4, lat: 47.615363, long: -122.333554, timestamp: "2018-02-01T17:21:08.000+08:00"}
      {sensorId: 5, lat: 47.615463, long: -122.333555, timestamp: "2018-02-01T17:21:09.000+08:00"}
    ]) {
    locationReadings {
      sensorId
      timestamp
      lat
      long
    }
    temperatureReadings {
      sensorId
      timestamp
      value
    }
  }
}

The problem is that the response returns null:

{
  "data": {
    "recordReadings": {
      "locationReadings": null,
      "temperatureReadings": null
    }
  }
}

Request Mapping Template:

## Convert tempReadings arguments to DynamoDB objects
#set($tempReadings = [])
#foreach($reading in ${ctx.args.tempReadings})
    $util.qr($tempReadings.add($util.dynamodb.toMapValues($reading)))
#end

## Convert locReadings arguments to DynamoDB objects
#set($locReadings = [])
#foreach($reading in ${ctx.args.locReadings})
    $util.qr($locReadings.add($util.dynamodb.toMapValues($reading)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        "LocationReadingTable": $utils.toJson($locReadings),
        "TemperatureReadingTable": $utils.toJson($tempReadings)
    }
}

Response Mapping Template:

## If there was an error with the invocation
## there might have been partial results
#if($ctx.error)
    ## Append a GraphQL error for that field in the GraphQL response
    $utils.appendError($ctx.error.message, $ctx.error.message)
#end
## Also returns data for the field in the GraphQL response
$utils.toJson($context.result.data)

The code is pretty much identical to the tutorial. I checked the logs and the response is being sent but it's not being captured so either my code is off or there is a bug on AWS's side. Can anyone reproduce this or is able to get a response when doing a multi-table BatchPutItem?

1

1 Answers

2
votes

Thank you for a very detailed question, it certainly helped me debug your issue. So, in order to fix your issue, you need to tweak your response mapping template. I was able to reproduce the issue with null response on my end. The reason being that the shape of the multi-table batch put response is of this format:

"result": {
    "data": {
        "TemperatureReadingTable": [
            {
                "value": 85.5,
                "sensorId": "1",
                "timestamp": "2018-02-01T17:21:05.000+08:00"
            },
            {
                "value": 85.7,
                "sensorId": "2",
                "timestamp": "2018-02-01T17:21:06.000+08:00"
            },
            {
                "value": 85.8,
                "sensorId": "3",
                "timestamp": "2018-02-01T17:21:07.000+08:00"
            },
            {
                "value": 84.2,
                "sensorId": "4",
                "timestamp": "2018-02-01T17:21:08.000+08:00"
            },
            {
                "value": 81.5,
                "sensorId": "5",
                "timestamp": "2018-02-01T17:21:09.000+08:00"
            }
        ],
        "LocationReadingTable": [
            {
                "lat": 47.615063,
                "long": -122.333551,
                "sensorId": "1",
                "timestamp": "2018-02-01T17:21:05.000+08:00"
            },
            {
                "lat": 47.615163,
                "long": -122.333552,
                "sensorId": "2",
                "timestamp": "2018-02-01T17:21:06.000+08:00"
            },
            {
                "lat": 47.615263,
                "long": -122.333553,
                "sensorId": "3",
                "timestamp": "2018-02-01T17:21:07.000+08:00"
            },
            {
                "lat": 47.615363,
                "long": -122.333554,
                "sensorId": "4",
                "timestamp": "2018-02-01T17:21:08.000+08:00"
            },
            {
                "lat": 47.615463,
                "long": -122.333555,
                "sensorId": "5",
                "timestamp": "2018-02-01T17:21:09.000+08:00"
            }
        ]
    },

So, the $context.result.data will return you an object with TemperatureReadingTable and LocationReadingTable as its fields. However, you are applying $util.toJson to resolve the type RecordResult, which has temperatureReadings and locationReadings as child fields.

Please update your Response Mapping template with the following definition, and it will work for you:

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

  {
      "temperatureReadings": $util.toJson(${ctx.result.data.TemperatureReadingTable}),
      "locationReadings": $util.toJson(${ctx.result.data.LocationReadingTable})
  }

Moreover, I'd encourage you enable CloudWatch logs from the Settings page of the Console, with ALL as the option. This will log Request/Response headers, the resolved Request/Response templates, Tracing information, etc. So it'll help you identify issues like these quickly by looking at the content of the request/response templates.

Thank you for bringing this issue, we will update the documentation, if it does not mention this.