Attaching Update and Delete Resolver for Our Mutations

In previous tutorial we added resolvers for createUser mutation and users query., It's time we add resolver for updateUser mutation and deleteUser mutation.

This will be quick., Open the AppSync API (TodoApplication) we created, Goto its Schema page and there in the Data Types filter types input enter Mutation. Now we can see all the mutations we have created.


Linking our updateUser Mutation to the Resolver:

Next to field updateUser(...): User click on the Attach button.

That will open a Create new Resolver page, In Data source name select UserTable

In Configure the request mapping template dropdown Don't select anything ;), Just copy the code below and paste it in the textarea.

{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : { "S" : "${context.arguments.id}" }
    },

    ## Set up some space to keep track of things we're updating **
    #set( $expNames  = {} )
    #set( $expValues = {} )
    #set( $expSet = {} )
    #set( $expAdd = {} )
    #set( $expRemove = [] )

    ## Iterate through each argument, skipping "id" and "expectedVersion" **
    #foreach( $entry in $context.arguments.entrySet() )
        #if( $entry.key != "id" )
            #if( (!$entry.value) && ("$!{entry.value}" == "") )
                ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **

                #set( $discard = ${expRemove.add("#${entry.key}")} )
                $!{expNames.put("#${entry.key}", "$entry.key")}
            #else
                ## Otherwise set (or update) the attribute on the item in DynamoDB **

                $!{expSet.put("#${entry.key}", ":${entry.key}")}
                $!{expNames.put("#${entry.key}", "$entry.key")}
                $!{expValues.put(":${entry.key}", { "S" : "${entry.value}" })}
            #end
        #end
    #end

    ## Start building the update expression, starting with attributes we're going to SET **
    #set( $expression = "" )
    #if( !${expSet.isEmpty()} )
        #set( $expression = "SET" )
        #foreach( $entry in $expSet.entrySet() )
            #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
            #if ( $foreach.hasNext )
                #set( $expression = "${expression}," )
            #end
        #end
    #end

    ## Continue building the update expression, adding attributes we're going to ADD **
    #if( !${expAdd.isEmpty()} )
        #set( $expression = "${expression} ADD" )
        #foreach( $entry in $expAdd.entrySet() )
            #set( $expression = "${expression} ${entry.key} ${entry.value}" )
            #if ( $foreach.hasNext )
                #set( $expression = "${expression}," )
            #end
        #end
    #end

    ## Continue building the update expression, adding attributes we're going to REMOVE **
    #if( !${expRemove.isEmpty()} )
        #set( $expression = "${expression} REMOVE" )

        #foreach( $entry in $expRemove )
            #set( $expression = "${expression} ${entry}" )
            #if ( $foreach.hasNext )
                #set( $expression = "${expression}," )
            #end
        #end
    #end

    ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
    "update" : {
        "expression" : "${expression}"
        #if( !${expNames.isEmpty()} )
            ,"expressionNames" : $utils.toJson($expNames)
        #end
        #if( !${expValues.isEmpty()} )
            ,"expressionValues" : $utils.toJson($expValues)
        #end
    }
}

Woah, That's a lot of code just for updating record, Indeed. Anyways let's go through it.

"operation" : "UpdateItem",

Here we're setting the operation to UpdateItem, For adding/creating records it was PutItem, This tells DynamoDB to update the record instead of creating new record.

"key" : {
    "id" : { "S" : "${context.arguments.id}" }
},

This just specifies the ID of the record, Based on this id our record will be updated., If we had chosen another field as our primary key, We would add that field here instead of id.

id field gets its value from the GraphQL mutation., Remeber we had made id field as required in our schema so we must provide it.

All the code after it key is provided by AWS (I went through their documentation), What it does is:

  • Removes the ID field so it wont be updated., We cannot update the ID once set and if we try to update it error will be thrown.
  • Removes all the fields with empty value, We cannot set empty values in DynamoDB.
  • If we have new field which doesn't exist in the record, It will be created
  • If we are updating an existing field, It will be updated
  • Next, It builds the expression that's used to either SET or UPDATE the field. This is important in DynamoDB
  • Finally it passes the expression, fields, values to the update object.
  • And this updates our record.

If I had known it would take so much time just to insert/update the record, I would have used MongoDB rather than DynamoDB.

This doesn't mean DynamoDB is bad, It just means I would have preferred something easy, simple and what I was already experienced with.

Moving on, In the Configure the response mapping template. textarea enter the following code

$util.toJson($context.result)

This will pass in the response as it receives from the resolver.

Your page will look something like the screenshot below.

AWS AppSync - updateUser Mutation Resolver

Now hit that Save button.

Testing our updateUser Mutation

If you remember we had added two users in our previous tutorial, Let's update one of those users now.

Open the Queries page and run this query

query {
  users {
    id
    name
    email
    phone
    address
  }
}

We cannot select password field, As we have not defined it in our User Type

We will see the following result.

{
  "data": {
    "users": [
      {
        "id": "4a09a4f6-2821-40dd-9525-d699d7801714",
        "name": "Jane Smith",
        "email": "jane.smith@gmail.com",
        "phone": "9876543210",
        "address": null
      },
      {
        "id": "f20057e6-0a78-4abb-b6c2-9f3d29d83d90",
        "name": "John Doe",
        "email": "john.doe@gmail.com",
        "phone": null,
        "address": "Bangalore"
      }
    ]
  }
}

Let's update Jame Smiths 4a09a4f6-2821-40dd-9525-d699d7801714 record by executing the code below.

Do remember your ID will be different, So use your own users ID

mutation {
  updateUser(
    id:"4a09a4f6-2821-40dd-9525-d699d7801714"
    phone: "+123-456-7890"
    address: "Internet"
  ) {
    id
    name
    email
    phone
    address
  }
}

And we see the following response.

{
  "data": {
    "updateUser": {
      "id": "4a09a4f6-2821-40dd-9525-d699d7801714",
      "name": "Jane Smith",
      "email": "jane.smith@gmail.com",
      "phone": "+123-456-7890",
      "address": "Internet"
    }
  }
}

Update mutation worked beautifully.


Linking our deleteUser Mutation to the Resolver:

Actually this is already linked., This happened when we used Create Resources for our Schema., Remeber it created few Queries and Mutations for us, deleteUser mutation was one of them.

Anyways I am using this as it matches our naming convention., If you want/named your delete mutation something else, Just click on Attach button beside the mutation.

For Resolver Data source name, Select UserTable and for Configure the request mapping template. enter the following code.

{
    "version" : "2017-02-28",
    "operation" : "DeleteItem",
    "key": {
        "id": { "S" : "${context.arguments.id}"}
    }
}

For Configure the response mapping template. enter the following code

$utils.toJson($context.result)

That's it., Thats all we need to do to delete a record., Let's test it.

Testing our deleteUser Mutation

Let's delete our user Jane Smith with id 4a09a4f6-2821-40dd-9525-d699d7801714 Open the Queries page and run this mutation

mutation {
  deleteUser(id: "4a09a4f6-2821-40dd-9525-d699d7801714") {
    id
    name
    email
  }
}

And we see the following response.

{
  "data": {
    "deleteUser": {
      "id": "4a09a4f6-2821-40dd-9525-d699d7801714",
      "name": "Jane Smith",
      "email": "jane.smith@gmail.com"
    }
  }
}

Now, If we run our users query again

query {
  users {
    id
    name
    email
    phone
    address
  }
}

We will see the following response

{
  "data": {
    "users": [
      {
        "id": "f20057e6-0a78-4abb-b6c2-9f3d29d83d90",
        "name": "John Doe",
        "email": "john.doe@gmail.com",
        "phone": null,
        "address": "Bangalore"
      }
    ]
  }
}

Users array has only one user, Our record was successfully removed from Database.


Exercise

Now, you have all the information you need for adding resolvers to Queries and Mutations.

You can try adding the resolvers for remaining Queries and Mutations., Anyways if you're not into doing exercises I will be posting the code for this in next tutorial.

With this we will call it a day.


Feedback:

It's important for me to hear your feedback (don't know why)., I will be implementing Authentication in later tutorials and Initially I wanted to use our Users table for that, That's the purpose of having users table.

Anyways I was speaking with someone and realized Using AWS Cognito might serve better as we can use it for creating users locally or via social media accounts.

And since we're using the AWS Stack, It makes much more sense.

If you have any thoughts on this, Just comment below or let me know.

Meta Information

This article was published on December 20, 2017 at 12:30 AM and is written by Dhruv Kumar Jha (me).
This is part of series: Building a Todo Application using GraphQL and AWS AppSync
Tags
GraphQL
AWS
AppSync
AWS AppSync