Search code examples
amazon-web-servicesamazon-dynamodbaws-appsync

How to autogenerate global ID using AppSync + DynamoDB


How do I generate ID automatically when I use AppSync and DynamoDB as the database source?

I have a type looking like below

type Post {
    id: ID!
    creator: String!
    createdAt: String!
    like: Int!
    dislike: Int!
    frozen: Boolean!
}

and input looking like below

input CreatePostInput {
    id: ID!
    creator: String!
    createdAt: String!
    like: Int!
    dislike: Int!
    frozen: Boolean!
}

and my mutation is obviously the combination of the two

createPost(input: CreatePostInput!): Post

However, when I make inserts I have to do something like below

mutation createPost{
  createPost(input:{
    id:2
    creator:"some creator"
    createdAt:"some date"
    like:0
    dislike:0
    frozen:false
  }){
    id
    creator
    createdAt
    like
    dislike
    frozen
  }
}

There is no way I can insert a post without having to know what the id is up to right now. Is there a way I can provide null or any random id and DynamoDB or AppSync automatically create the next index before inserting into the table?

Error generated when I update the input CreatePostInput to not accept any ID

{
  "data": {
    "createPost": null
  },
  "errors": [
    {
      "path": [
        "createPost"
      ],
      "data": null,
      "errorType": "DynamoDB:AmazonDynamoDBException",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "One or more parameter values were invalid: Type mismatch for key id expected: S actual: NULL (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 629QEM7MH9BRAJ9MHU3FM1S0U3VV4KQNSO5AEMVJF66Q9ASUAAJG)"
    }
  ]
}

My Resolver Template

{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        ## If object "id" should come from GraphQL arguments, change to $util.dynamodb.toDynamoDBJson($ctx.args.id)
        "id": $util.dynamodb.toDynamoDBJson($util.autoId()),
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}

Solution

  • First, update the createPost resolver as:

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

    Then, remove the id field from your CreatePostInput input type:

    input CreatePostInput {
      creator: String!
      createdAt: String!
      like: Int!
      dislike: Int!
      frozen: Boolean!
    }
    

    Save both the changes and you should be done.

    If you're the one of seeing-is-believing guys like me, take a look at this egghead.io video.