2
votes

I have an AppSync GraphQL API that makes a Query to a DynamoDB and returns a JSON String, however in my Response Mapping Template I use the built-in $util.parseJson() function as listed here - but I'm still returned a JSON string in the Query window and when requesting the data in my React app.

Schema file, I have an ordinary ID & Address field that is of type AWSJSON.

type Venue {
  id: ID!
  address: AWSJSON
}

When running a mutation, I usually run the address object through a quick JSON.stringify(addressObj) and that formats the object as a string with the \"\" escaped, meaning that it can be inserted into DynamoDB.

Request Mapping template

{
  "version": "2017-02-28",
  "operation": "GetItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
  }
}

Response Mapping template

#set($result = $ctx.result)

## address - parse back to JSON
#set($result.address = $util.parseJson($ctx.result.address))

## Return the result
$util.toJson($result)

The idea to create a new variable and then assign the value to the parseJSON value was taken from How return JSON object from DynamoDB with appsync?. So, as seen below, I am parsing the value through what seems to be the correct method to turn it from stringified JSON, to an object - but it doesn't appear to work.

The current response:

{
  "data": {
    "getVenue": {
      "id": "31538150",
      "address": "{\"lng\":-1.54511300000001,\"postcode\":\"LS1 5DL\",\"short\":\"New Station St., LS1\",\"lat\":53.795231,\"full\":\"16 New Station St, Leeds LS1 5DL, UK\"}"
    }
  }
}

Whereas the response that I am wanting is...

{
  "data": {
    "getVenue": {
      "id": "31538150",
      "address": { "lng": -1.54511300000001, "postcode": "LS1 5DL", "short": "New Station St., LS1", "lat": 53.795231, "full": "16 New Station St, Leeds LS1 5DL, UK" }
    }
  }
}

Any help is greatly appreciated!

1
If you look at this documentation AWJSON represents a JSON string. It also says that they will automatically be parsed and loaded in the resolver mapping templates as Maps, Lists, or Scalar values rather than as the literal input strings.Lisa M Shon
@LisaMShon Thanks, so rather than stringifying the JSON before the mutation, do you need to just simply provide JSON to the mutation, then have a step within the resolver mapping template to stringify it, before it's saved into Dynamo?Tom Hanson
@TomHanson intuition suggests that you have stringified address more times than you intended. A temporary test to confirm this might be #set($result.address = $util.parseJson($util.parseJson($ctx.result.address)))Michael - sqlbot

1 Answers

1
votes

Old question but thought I would add some notes...

AWSJSON is a string value that will be parsed into DynamoDB as JSON and stringified again on fetching.

So AppSync expects a string (stringified JSON) for inputs and will return a string that can be parsed with JSON.parse.

However this data is parsed before storing in DynamoDB. So of you query DynamoDB separately than through AppSync then you can query it like it was an object. Same with inputing directly into DynamoDB.

The only way to get JSON in the AppSync result is to define each and every field in GraphQL. Sometimes this can be achieved by restructuring data. For example instead of storing:

{
   bob: { age: 34 },
   igor: { age: 124 }
}

Which would need to be stringified as an AWSJSON field. It can however be restructured like this:

[{
   name: 'bob',
   age: 34
 }, { 
   name: 'igor',
   age: 123
}]

Which can be defined in GraphQL as something like this:

type User {
  age: Int,
  name: String
}

So that one can now extract specific value such as age from the GraphQL without involving and JSON parse/stringify.