6

How I can get JSON object in response from DynamoDB ? I store data in DB as array of object in format JSON. I have next mapping template request

{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
  "userId": {
    "S":  "$context.identity.username"
  }
},
  #set( $attrs = $util.dynamodb.toMapValues($ctx.args))
  #set( $attrs.categories = $util.dynamodb.toDynamoDB($ctx.args.categories))

  "attributeValues": $util.toJson($attrs)
}

and mapping template response

#set( $result = $ctx.result)
#set( $result.categories = $util.parseJson($ctx.result.categories))
$util.toJson($result)

but I got response in the format DynamoDB JSON

"createItem": {
      "title": "Test 1",
       "categories": "[{name=food, id=2}, {name=eat, id=1}]"
    }

in dynamoDB date save as

"categories": {
    "L": [
      {
        "M": {
          "id": {
            "S": "2"
          },
          "name": {
            "S": "food"
          }
        }
      },
      {
        "M": {
          "id": {
            "S": "1"
          },
          "name": {
            "S": "eat"
          }
        }
      }
    ]
  }

How parse it to normal JSON or object ?

1 Answer 1

4

In your current mapping template, you are storing categories as a "S" in DDB which means string and this is why you are getting a stringified version of the DynamoDB list. Assuming you are running a mutation that looks something like this:

mutation {
  create(input: { title: "Test 1", categories: [{ name: "category 1" }] }) {
    title
    categories {
      name
    }
  }
}

Then you should change your mapping template to this:

{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
    "userId": {
      "S":  "$context.identity.username"
    }
  },
  "attributeValues": $util.toJson($ctx.args)
}

The above template can be used if you want to store the data as DynamoDB Lists and Maps. If you are instead trying to store your JSON as a JSON stringified blob in a DynamoDB "S" attribute but without the L's and M's then instead change your template to this:

{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
    "userId": {
      "S":  "$context.identity.username"
    }
  },
    #set( $attrs = $util.dynamodb.toMapValues($ctx.args))

    ## NOTE: The $util.toJson instead of the dynamodb version which adds L, M, S, etc
    #set( $attrs.categories = { "S":  "$util.toJson($ctx.args.categories)"})
    "attributeValues": $util.toJson($attrs)
}

And then in the response mapping template, you will need to parse the JSON to returned structured JSON instead of a JSON stringified string.

## Get the result and parse categories into structured objects.
#set( $result = $ctx.result)
#set( $result.categories = $util.parseJson($ctx.result.categories))

## Return the full JSON payload
$util.toJson($result)

EDIT (More Details):

I have these schema parts (note this is not complete):

type Category {
    name: String
}

input CategoryInput {
    name: String
}

input CreatePostInput {
    title: String
    categories: [CategoryInput]
}

type Post {
    id: ID!
    title: String
    categories: [Category]
}

type Mutation {
    createPost(input: CreatePostInput!): Post
}

And this request mapping template exactly:

## Mutation.createPost request mapping template
#set( $attrs = $util.dynamodb.toMapValues($ctx.args.input))
#set( $attrs.categories = { "S":  "$util.toJson($ctx.args.input.categories)"})

{
  "version": "2017-02-28",
  "operation": "PutItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($util.autoId()),
  },
  "attributeValues": $util.toJson($attrs),
  "condition": {
    "expression": "attribute_not_exists(#id)",
    "expressionNames": {
      "#id": "id",
    },
  },
}

And this response mapping template

## Mutation.createPost response mapping template
## Get the result and parse categories into structured objects.
#set( $result = $ctx.result)
#set( $result.categories = $util.parseJson($ctx.result.categories))

## Return the full JSON payload
$util.toJson($result)

I was then able to run this query:

mutation {
  createPost(input: {
    title: "Hello, world!",
    categories: [
      {
        name: "cat1"
      }
    ]
  }) {
    id
    title
    categories {
      name
    }
  }
}

and got this response:

{
  "data": {
    "createJSONTest2": {
      "id": "c72ff226-0d67-41c4-9c47-784955a64bc5",
      "title": "Hello, world!",
      "categories": [
        {
          "name": "cat1"
        }
      ]
    }
  }
}

when I go to the DynamoDB console this is stored as the category attribute

[{"name":"cat1"}]

It appears this is all working correctly. Lmk if you need further help debugging.

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks !! The second variant works for me. but when I use $util.parseJson($ctx.result.categories) I got result "categories": "[{id=1, name=category 1}, {id=2, name=category 2}]" It's not JSON ..
$util.parseJson() returns a map which should only become valid JSON once you call $util.toJson() on it. Can you share your response mapping template that yielded the above? The last line $util.toJson($result) I believe should JSONify the entire nested structure.
I use response template witch you wrote. #set( $result = $ctx.result) #set( $result.categories = $util.parseJson($ctx.result.categories)) $util.toJson($result)
ok thank you. let me investigate as this is not desired behavior.
Hmm I was able to reproduce this and it looks like it is working correctly for me. I will update the answer with more details including the schema and query that I ran so you can debug.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.