Let's recap, This is what we have done till now
createUser
mutationusers
Query.updateUser
mutationdeleteUser
mutationAnd this is what we have left to do?
user
QuerycreateList
mutationupdateList
mutationdeleteList
mutationlists
Querylist
QuerycreateItem
mutationupdateItem
mutationdeleteItem
mutationitems
Queryitem
QueryWe have a lot to do., I mean we have lot of repetitive work to do.
We have already covered these in previous tutorials so I won't be explaining these in details, If you're new just look at previous tutorials.
Let's Begin.
user
Query to the Resolver:In Schema page, Click on Attach button next to field user: User
, Select UserTable as Data source name.
In Configure the request mapping template paste in the below code.
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": { "S": "$context.arguments.id" }
}
}
For Configure the response mapping template enter this code
$util.toJson($context.result)
And hit that Save Button., That's it we're done with this.
Let's test this by running the query (f20057e6-0a78-4abb-b6c2-9f3d29d83d90
is the id of user from the database, right now we only have one user.)
query {
user(id: "f20057e6-0a78-4abb-b6c2-9f3d29d83d90") {
id
name
email
phone
address
}
}
After we execute the query, We see this response.
{
"data": {
"user": {
"id": "f20057e6-0a78-4abb-b6c2-9f3d29d83d90",
"name": "John Doe",
"email": "john.doe@gmail.com",
"phone": null,
"address": "Bangalore"
}
}
}
We successfully attached resolver to our query.
List
Type and Item
TypeIn Schema page, Click on Create Resources button, It will open Create Resources page.
In there for Select a type field select List
. As soon as you select in new fields will appear.
For Create a table to hold values for the List type filed you can see it prefilled it with ListTable
which is fine.
For Configure the ListTable DynamoDB table section, Leave everything as is.
For We will add the following to your schema field, We don't need it but there's nothing we can do as AppSync will add it irrespective of our usage.
Now click on that Create Button. AppSync will create the required table for us.
Repeat the same process for Item type.
For Create a table to hold values for the Item type make sure its
ItemTable
And we have created tables for both of our List and Item Types.
createList
, updateList
, deleteList
Mutations to the Resolver:Open Schema page, Click on Attach button next to createList(...): List
(in Data Types section)
In Create new resolver page for Data source name select ListTable
For Configure the request mapping template Field, Paste the below code
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
## If your table's hash key is not named 'id', update it here. **
"id": { "S": "$util.autoId()"}
## If your table has a sort key, add it as an item here. **
},
#set( $expValues = {} )
#foreach( $entry in $context.arguments.entrySet() )
$!{expValues.put("${entry.key}", { "S" : "${entry.value}" })}
#end
#if( !${expValues.isEmpty()} )
"attributeValues" : $utils.toJson($expValues)
#end
}
For Configure the response mapping template field, Paste this code
$util.toJson($context.result)
And click on the Save button.
updateList(...): List
Repeat the same steps, But for the field Configure the request mapping template Use this code
{
"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
}
}
deleteList(...): List
Do Nothing, As this was already created by AppSync when we created the resources.
lists
and list
Queries to the Resolver:Click on Attach button next to lists: [List]
and for Data source name select ListTable
.
For Configure the request mapping template field enter the below code
{
"version" : "2017-02-28",
"operation" : "Scan",
## Add 'limit' and 'nextToken' arguments to this field in your schema to implement pagination. **
"limit": #if(${context.arguments.limit}) ${context.arguments.limit} #else 20 #end,
"nextToken": #if(${context.arguments.nextToken}) "${context.arguments.nextToken}" #else null #end
}
For Configure the response mapping template field, Enter this code
$utils.toJson($context.result.items)
And then click on the Save button.
No do the same for list(...): List
Query, but for field Configure the request mapping template enter this code
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": { "S": "$context.arguments.id" }
}
}
And for field Configure the response mapping template
$util.toJson($context.result)
And we have successfully added resolvers for our queries.
createItem
, updateItem
, deleteItem
Mutations to the Resolver:Open Schema page, Click on Attach button next to createItem(...): Item
(in Data Types section)
In Create new resolver page for Data source name select ItemTable
For Configure the request mapping template Field, Paste the below code
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
## If your table's hash key is not named 'id', update it here. **
"id": { "S": "$util.autoId()"}
## If your table has a sort key, add it as an item here. **
},
#set( $expValues = {} )
#foreach( $entry in $context.arguments.entrySet() )
$!{expValues.put("${entry.key}", { "S" : "${entry.value}" })}
#end
#if( !${expValues.isEmpty()} )
"attributeValues" : $utils.toJson($expValues)
#end
}
For Configure the response mapping template field, Paste this code
$util.toJson($context.result)
And click on the Save button.
updateItem(...): Item
Repeat the same steps, But for the field Configure the request mapping template Use this code
{
"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
}
}
deleteItem(...): Item
Do Nothing, As this was already created by AppSync when we created the resources.
items
item list
Queries to the Resolver:Click on Attach button next to items: [Item]
and for Data source name select ItemTable
.
For Configure the request mapping template field enter the below code
{
"version" : "2017-02-28",
"operation" : "Scan",
## Add 'limit' and 'nextToken' arguments to this field in your schema to implement pagination. **
"limit": #if(${context.arguments.limit}) ${context.arguments.limit} #else 20 #end,
"nextToken": #if(${context.arguments.nextToken}) "${context.arguments.nextToken}" #else null #end
}
For Configure the response mapping template field, Enter this code
$utils.toJson($context.result.items)
And then click on the Save button.
No do the same for item(...): Item
Query, but for field Configure the request mapping template enter this code
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": { "S": "$context.arguments.id" }
}
}
And for field Configure the response mapping template
$util.toJson($context.result)
We have successfully added resolvers for our queries.
And with this we're done Attaching resolvers to our Queries and Mutations.
Let's test everything we did by running these Mutations and Queries.
Let's start by adding new user with this Query
mutation {
createUser(
name: "Dhruv"
email: "dhruv@internet.com"
password: "pass123"
) {
id
name
email
}
}
This will return the response
{
"data": {
"createUser": {
"id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Dhruv",
"email": "dhruv@internet.com"
}
}
}
Everything we do from this point will be related to this user, List Type needs a user id and Item Type needs a List id.
I made few changes to the Designing our Schema tutorial, be sure to check and update the Schema code from there so you're up to doate.
Let's create few Lists for our user with id 5b0fc184-f11d-4342-ab4f-95721e9ee831
by running this code.
mutation {
createList(
user_id: "5b0fc184-f11d-4342-ab4f-95721e9ee831"
name: "Tutorial Ideas"
description: "These are some of the tutorial ideas I have"
) {
id
name
description
}
}
And we get the expected response (which is always good)
{
"data": {
"createList": {
"id": "bee5f479-e875-4090-8de4-704f0ba746c1",
"name": "Tutorial Ideas",
"description": "These are some of the tutorial ideas I have"
}
}
}
Let's run few more mutations
mutation FavList{
createList(
user_id: "5b0fc184-f11d-4342-ab4f-95721e9ee831"
name: "Favourite Websites"
description: "These are my Favorite Websites"
) {
id
name
description
}
}
mutation TechStack{
createList(
user_id: "5b0fc184-f11d-4342-ab4f-95721e9ee831"
name: "Favourite TechStack"
description: "These are my Favorite Tech"
) {
id
name
description
}
}
Now if we run
query {
lists {
id
name
description
}
}
We see the following response
{
"data": {
"lists": [
{
"id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"name": "Favourite TechStack",
"description": "These are my Favorite Tech"
},
{
"id": "bee5f479-e875-4090-8de4-704f0ba746c1",
"name": "Tutorial Ideas",
"description": "These are some of the tutorial ideas I have"
},
{
"id": "319226f5-9600-46b9-9dea-f9c80e4c5db7",
"name": "Favourite Websites",
"description": "These are my Favorite Websites"
}
]
}
}
And if we run the query
query {
list(id: "b35a92cf-c627-4831-95f2-2cb9f58594fb") {
id
user_id
name
description
}
}
We get the following response.
{
"data": {
"list": {
"id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"user_id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Favourite TechStack",
"description": "These are my Favorite Tech"
}
}
}
Let's create few Items for our List with id b35a92cf-c627-4831-95f2-2cb9f58594fb
by running this code.
mutation {
createItem(
list_id: "b35a92cf-c627-4831-95f2-2cb9f58594fb"
name: "React JS"
description: "In computing, React is a JavaScript library for building user interfaces. It is maintained by Facebook, Instagram and a community of individual developers and corporations"
date: "2017-12-20"
) {
id
name
description
date
}
}
mutation {
createItem(
list_id: "b35a92cf-c627-4831-95f2-2cb9f58594fb"
name: "GraphQL"
description: "GraphQL is a data query language developed internally by Facebook in 2012 before being publicly released in 2015. It provides an alternative to REST and ad-hoc webservice architectures."
date: "2017-12-20"
) {
id
name
description
date
}
}
mutation {
createItem(
list_id: "b35a92cf-c627-4831-95f2-2cb9f58594fb"
name: "AWS AppSync"
description: "AWS AppSync automatically updates the data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. AppSync makes it easy to build collaborative mobile and web applications that deliver responsive, collaborative user experiences."
date: "2017-12-20"
) {
id
name
description
date
}
}
Now if we run the query
query {
items {
id
name
description
}
}
We get the following response
{
"data": {
"items": [
{
"id": "81dcb364-de5e-43c0-a66b-913dd87b7c83",
"name": "GraphQL",
"description": "GraphQL is a data query language developed internally by Facebook in 2012 before being publicly released in 2015. It provides an alternative to REST and ad-hoc webservice architectures."
},
{
"id": "f8bafed8-fa57-438b-b8c1-95acaf375998",
"name": "AWS AppSync",
"description": "AWS AppSync automatically updates the data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. AppSync makes it easy to build collaborative mobile and web applications that deliver responsive, collaborative user experiences."
},
{
"id": "aae71b55-22f0-4cd5-bfc6-da870bdb5544",
"name": "React JS",
"description": "In computing, React is a JavaScript library for building user interfaces. It is maintained by Facebook, Instagram and a community of individual developers and corporations"
}
]
}
}
And if we run the query
query {
item(id: "f8bafed8-fa57-438b-b8c1-95acaf375998") {
id
name
description
}
}
We get the repsonse
{
"data": {
"item": {
"id": "f8bafed8-fa57-438b-b8c1-95acaf375998",
"name": "AWS AppSync",
"description": "AWS AppSync automatically updates the data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. AppSync makes it easy to build collaborative mobile and web applications that deliver responsive, collaborative user experiences."
}
}
}
Let's test our Update Mutations by running this query
mutation {
updateList(
id:"bee5f479-e875-4090-8de4-704f0ba746c1"
name:"Awesome Tutorial Ideas"
) {
id
name
}
}
We see the response
{
"data": {
"updateList": {
"id": "bee5f479-e875-4090-8de4-704f0ba746c1",
"name": "Awesome Tutorial Ideas"
}
}
}
And if we run the query
mutation {
updateItem(
id:"81dcb364-de5e-43c0-a66b-913dd87b7c83"
name:"Awesome GraphQL"
) {
id
name
}
We get the response
{
"data": {
"updateItem": {
"id": "81dcb364-de5e-43c0-a66b-913dd87b7c83",
"name": "Awesome GraphQL"
}
}
}
Run the query
query {
users {
id
name
email
}
lists {
id
user_id
name
description
}
items {
id
list_id
name
description
}
user(id: "5b0fc184-f11d-4342-ab4f-95721e9ee831") {
name
email
phone
}
list(id: "b35a92cf-c627-4831-95f2-2cb9f58594fb") {
name
description
}
item(id: "81dcb364-de5e-43c0-a66b-913dd87b7c83") {
name
description
}
}
And we get our response
{
"data": {
"users": [
{
"id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Dhruv",
"email": "dhruv@internet.com"
},
{
"id": "f20057e6-0a78-4abb-b6c2-9f3d29d83d90",
"name": "John Doe",
"email": "john.doe@gmail.com"
}
],
"lists": [
{
"id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"user_id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Favourite TechStack",
"description": "These are my Favorite Tech"
},
{
"id": "bee5f479-e875-4090-8de4-704f0ba746c1",
"user_id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Awesome Tutorial Ideas",
"description": "These are some of the tutorial ideas I have"
},
{
"id": "319226f5-9600-46b9-9dea-f9c80e4c5db7",
"user_id": "5b0fc184-f11d-4342-ab4f-95721e9ee831",
"name": "Favourite Websites",
"description": "These are my Favorite Websites"
}
],
"items": [
{
"id": "81dcb364-de5e-43c0-a66b-913dd87b7c83",
"list_id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"name": "Awesome GraphQL",
"description": "GraphQL is a data query language developed internally by Facebook in 2012 before being publicly released in 2015. It provides an alternative to REST and ad-hoc webservice architectures."
},
{
"id": "f8bafed8-fa57-438b-b8c1-95acaf375998",
"list_id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"name": "AWS AppSync",
"description": "AWS AppSync automatically updates the data in web and mobile applications in real time, and updates data for offline users as soon as they reconnect. AppSync makes it easy to build collaborative mobile and web applications that deliver responsive, collaborative user experiences."
},
{
"id": "aae71b55-22f0-4cd5-bfc6-da870bdb5544",
"list_id": "b35a92cf-c627-4831-95f2-2cb9f58594fb",
"name": "React JS",
"description": "In computing, React is a JavaScript library for building user interfaces. It is maintained by Facebook, Instagram and a community of individual developers and corporations"
}
],
"user": {
"name": "Dhruv",
"email": "dhruv@internet.com",
"phone": null
},
"list": {
"name": "Favourite TechStack",
"description": "These are my Favorite Tech"
},
"item": {
"name": "Awesome GraphQL",
"description": "GraphQL is a data query language developed internally by Facebook in 2012 before being publicly released in 2015. It provides an alternative to REST and ad-hoc webservice architectures."
}
}
}
We tested all of our Queries and Mutations and all of them are working.
So are we done?
We're almost done., I might write another Tutorial on this (Backend) or move onto the Frontend
Although in future tutorials we will get back to this and make changes to our Schema as required.
And with this Ladies and Gentlemen We have a Fully functional serverless GraphQL endpoint up and running.
Ofcourse you can't use it unless you're authenticated.., So I guess I have to write another tutorial on this.
Until then, Keep Learning.
December 20, 2017 at 02:20 PM
and is written by Dhruv Kumar Jha (me).