Mastering AWS AppSync Lambda Resolvers: Develop Your GraphQL APIs with Them

Dive into the capabilities of AWS AppSync Lambda resolvers to seamlessly integrate AWS Lambda functions for dynamic data fetching and custom business logic in your GraphQL APIs.

Introduction:

you can connect your existing tables to a GraphQL schema by creating a data source and a resolver. In either case, you’ll be able to read and write to your DynamoDB database through GraphQL statements and subscribe to real-time data.

There are specific configuration steps that need to be completed in order for GraphQL statements to be translated to DynamoDB operations, and for responses to be translated back into GraphQL. This tutorial outlines the configuration process through several real-world scenarios and data access patterns.

Create a DynamoDB Table named “posts”

We have two runtime environments for appsync resolvers 

  • Appsync VTL
  • Appsync JS

AppSync VTL:

AWS AppSync uses resolvers to handle GraphQL fields. Sometimes, you need to perform multiple operations to resolve one GraphQL field. With pipeline resolvers, you can combine these operations in a sequence. For example, you might need to check authorization before fetching data for a field.

A pipeline resolver consists of three parts: 

  1. Before mapping template: This is where you can perform some actions before the main operation.
  2. After mapping template: This is where you can do things after the main operation, like formatting the response.
  3. Functions: These are the individual operations you want to perform in order. Each function has a request and response mapping template that tells AppSync how to work with the data.

Pipeline resolvers are helpful when you have a chain of actions to perform for a single field, and you can use them for various tasks, including authorization checks and data fetching. Keep in mind that they are not linked to a specific data source; instead, they’re composed of units called functions that execute tasks against your data sources.

AppSync JS:

AWS AppSync is a service that helps you respond to GraphQL requests, which are queries and mutations that interact with your data sources. To make this work, you need resolvers. Think of resolvers as the middlemen between GraphQL and your data source. They know how to take a GraphQL request, turn it into instructions for your data source, and then turn the data source’s response into a GraphQL response. 

In AWS AppSync, you can create these resolvers using JavaScript, and they run in an environment provided by AWS AppSync. You can write simple, individual resolvers or build complex ones by chaining multiple functions in a pipeline. These resolvers are the heart of your GraphQL API, making it possible to fetch and manipulate data in your data sources.

AppSync VTL DynamoDB Operations

Query:listPosts

listposts.request.vtl

{
    "operation" : "Query",
    "query" : {
        ## Provide a query expression. 
        "expression": "PK = :PK and SK = :SK",
        "expressionValues" : {
            ":PK" : $util.dynamodb.toDynamoDBJson($ctx.args.PK),
	":SK"  :  $util.dynamodb.toDynamoDBJson($ctx.args.SK),
        }
    }
}

listposts.response.vtl

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result.items)

The code provided, which consists of a request mapping template (listposts.request.vtl) and a response mapping template (listposts.response.vtl) for a GraphQL query named listPosts. These templates are used in AWS AppSync to map incoming requests and outgoing responses to and from a data source, typically Amazon DynamoDB in this case.

Request Mapping Template (listposts.request.vtl):

This mapping template defines how incoming GraphQL requests are translated into a format that can be understood by the data source, in this case, DynamoDB. Let’s break down the key components:

“operation” : “Query”: This specifies the operation to perform on the data source. In this case, it’s a DynamoDB query operation.
“expression”: This is a DynamoDB query expression. It defines the conditions that must be met for an item to be retrieved from the DynamoDB table. It uses placeholders :PK and :SK for the partition key and sort key.
“expressionValues”: Here, you’re defining values for the placeholders :PK and :SK using the arguments provided in the GraphQL request ($ctx.args.PK and $ctx.args.SK). These values are converted into DynamoDB-compatible JSON using $util.dynamodb.toDynamoDBJson().

Response Mapping Template (listposts.response.vtl):

This mapping template specifies how the response from the data source is transformed into a format suitable for a GraphQL response. Let’s break down its components:

#if($ctx.error): This conditional checks if there’s an error returned from the data source. If an error is present, it’s handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.
$util.toJson($ctx.result.items): Assuming there are no errors, this line takes the result from DynamoDB, represented as $ctx.result which has items array, and transforms it into a JSON format that can be returned as part of the GraphQL response. This is what the GraphQL client will receive as the result of the listPosts query.

In summary, these mapping templates for the listPosts query help bridge the gap between GraphQL and DynamoDB. They ensure that the query is correctly formatted and that the data source’s response is translated into a GraphQL-friendly format. These templates are crucial for making GraphQL and DynamoDB work together seamlessly within AWS AppSync.

GetItem:getPost

getPost.request.vtl

{
    "operation": "GetItem",
    "key": {
        "PK": $util.dynamodb.toDynamoDBJson($ctx.args.PK),
        "SK": $util.dynamodb.toDynamoDBJson($ctx.args.SK),
    }
}

getPost.response.vtl

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

The provided request mapping template (getPost.request.vtl) and response mapping template (getPost.response.vtl) for a GraphQL query named getPost. These templates are used in AWS AppSync to map requests to a data source, which, in this case, is typically Amazon DynamoDB.

Request Mapping Template (getPost.request.vtl):

This mapping template is responsible for defining how incoming GraphQL requests are transformed into a format that DynamoDB can understand. Here’s a detailed explanation:

“operation”: “GetItem”: This specifies the operation to be performed on the data source. In this case, it’s a DynamoDB GetItem operation, which is used to retrieve a specific item from a DynamoDB table.
“key”: This object defines the key of the item you want to retrieve from the DynamoDB table. The key is defined as an object with two attributes, “PK” (partition key) and “SK” (sort key). These values are obtained from the GraphQL arguments using $ctx.args.PK and $ctx.args.SK. The toDynamoDBJson function is used to convert these values into a format that DynamoDB understands.

Response Mapping Template (getPost.response.vtl):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

#if($ctx.error): This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.

$util.toJson($ctx.result): Assuming there are no errors, this line takes the result returned from DynamoDB (in the ctx.result object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL query. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the getPost query facilitate the translation of GraphQL requests and responses to and from DynamoDB. They ensure that the query is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format, allowing for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment.

putItem:createPost

createPost.request.vtl:

{
    "operation" : "PutItem",
    "key" : {
        "PK": $util.dynamodb.toDynamoDBJson($util.autoId()),
        "SK": $util.dynamodb.toDynamoDBJson("post#$ctx.args.postStatus"),
        "createdTime": $util.dynamodb.toDynamoDBJson($util.time.nowEpochSeconds()),
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}

createPost.response.vtl:

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

The provided request mapping template (`createPost.request.vtl`) and response mapping template (`createPost.response.vtl`) for a GraphQL mutation named `createPost`. These templates are used in AWS AppSync to map requests to a data source, which is often Amazon DynamoDB in this case.

Request Mapping Template (`createPost.request.vtl`):

This mapping template defines how incoming GraphQL mutation requests are translated into a format that DynamoDB can understand. Here’s a detailed explanation:

– `”operation”: “PutItem”`: This specifies the operation to be performed on the data source. In this case, it’s a DynamoDB `PutItem` operation, which is used to insert a new item into a DynamoDB table.
– `”key”`: This object defines the key of the item you want to insert into the DynamoDB table. It consists of three attributes:
       – `”PK”`: The partition key (PK) is set to a unique identifier generated using `$util.autoId()`. This ensures that each item inserted has a unique PK.
       – `”SK”`: The sort key (SK) is set to a value derived from the GraphQL argument `postStatus` using `”post#$ctx.args.postStatus”`. This is used to organize items in DynamoDB.
– `”createdTime”`: This attribute is set to the current epoch time, obtained using `$util.time.nowEpochSeconds()`. It records the creation time of the item.
– `”attributeValues”`: This object takes the arguments from the GraphQL request (in this case, `$ctx.args`) and converts them into a DynamoDB-compatible format using `$util.dynamodb.toMapValuesJson()`. This allows the GraphQL input data to be saved as attributes in the DynamoDB item.

Response Mapping Template (`createPost.response.vtl`):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

– `#if($ctx.error)`: This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using `$util.error()`. The error message and type are taken from the `ctx.error` object.

– `$util.toJson($ctx.result)`: Assuming there are no errors, this line takes the result returned from DynamoDB (in the `ctx.result` object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL mutation. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the `createPost` mutation facilitate the translation of GraphQL requests and responses to and from DynamoDB. They ensure that the mutation is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format. This allows for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment and is particularly useful for inserting new items into the DynamoDB table.

updateItem:updatePost

updatePost.request.vtl:

## Below example shows how to create an object from all provided GraphQL arguments
#set( $time = $util.time.nowEpochSeconds() )
$util.qr($ctx.args.input.put("updatedTime",$time))

{
  "version": "2017-02-28",
  "operation": "UpdateItem",
  "key": {
    "PK": $util.dynamodb.toDynamoDBJson($ctx.args.input.PK),
    "SK": $util.dynamodb.toDynamoDBJson($ctx.args.input.SK),
  },

  ## 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 keys 
  #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args.input, ["PK", "SK"]).entrySet() )
    #if( $util.isNull($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}", $util.dynamodb.toDynamoDB($entry.value))}
    #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
  },

  "condition": {
    "expression": "attribute_exists(#PK) AND attribute_exists(#SK)",
    "expressionNames": {
      "#PK": "PK",
      "#SK": "SK",
    },
  }
}

updatePost.response.vtl

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

The provided request mapping template (updatePost.request.vtl) and response mapping template (updatePost.response.vtl) for a GraphQL mutation named updatePost. These templates are used in AWS AppSync to map requests to a data source, typically Amazon DynamoDB in this case.

Request Mapping Template (updatePost.request.vtl):

This mapping template defines how incoming GraphQL mutation requests are translated into a format that DynamoDB can understand for an update operation. Here’s a detailed explanation:

$util.qr($ctx.args.input.put(“updatedTime”, $time)): This line adds an attribute named “updatedTime” to the input object with the current epoch time.

“version”: “2017-02-28”: This specifies the version of the request. In this case, it’s “2017-02-28,” which is the version of the AWS DynamoDB API used for the update operation.
“operation”: “UpdateItem”: This specifies the operation to be performed on the data source. In this case, it’s a DynamoDB UpdateItem operation, which is used to modify an existing item in the DynamoDB table.
“key”: This object defines the key of the item you want to update in the DynamoDB table. It consists of two attributes: “PK” and “SK,” which are taken from the input object provided in the GraphQL request.

The section starting with #set($expNames = {}) and ending with “expressionValues”: $utils.toJson($expValues), constructs the update expression for the DynamoDB update operation. It iterates through the attributes in the input object, handling different cases, such as setting, adding, or removing attributes. It dynamically builds the update expression based on the provided input.

“condition”: This section specifies a condition that must be met for the update to be executed. In this case, it checks that both the PK and SK attributes exist in the item to be updated.

Response Mapping Template (updatePost.response.vtl):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

#if($ctx.error): This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.

$util.toJson($ctx.result): Assuming there are no errors, this line takes the result returned from DynamoDB (in the ctx.result object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL mutation. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the updatePost mutation facilitate the translation of GraphQL requests and responses to and from DynamoDB for update operations. They ensure that the mutation is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format. This allows for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment and is particularly useful for modifying existing items in the DynamoDB table.

deleteItem:deletePost

deletePost.request.vtl:

{
    "operation" : "DeleteItem",
    "key" : {
        "PK" : { "S" : "${ctx.args.PK}" }
        "SK" : { "S" : "${ctx.args.SK}" }
    }
}

deletePost.response.vtl:

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

The provided request mapping template (deletePost.request.vtl) and response mapping template (deletePost.response.vtl) for a GraphQL mutation named deletePost. These templates are used in AWS AppSync to map requests to a data source, which, in this case, is typically Amazon DynamoDB.

Request Mapping Template (deletePost.request.vtl):

This mapping template defines how incoming GraphQL mutation requests are translated into a format that DynamoDB can understand for a delete operation. Here’s a detailed explanation:

“operation”: “DeleteItem”: This specifies the operation to be performed on the data source. In this case, it’s a DynamoDB DeleteItem operation, which is used to remove an item from a DynamoDB table.
“key”: This object defines the key of the item you want to delete from the DynamoDB table. It consists of two attributes, “PK” (partition key) and “SK” (sort key), which are taken directly from the ctx.args object provided in the GraphQL request.

The “S” and ${ctx.args.PK} format within the “key” object represents that the values of PK and SK are provided as strings in the request.

Response Mapping Template (deletePost.response.vtl):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

#if($ctx.error): This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.

$util.toJson($ctx.result): Assuming there are no errors, this line takes the result returned from DynamoDB (in the ctx.result object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL mutation. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the deletePost mutation facilitate the translation of GraphQL requests and responses to and from DynamoDB for delete operations. They ensure that the mutation is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format. This allows for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment, particularly for removing items from the DynamoDB table.

batchGetItem : getPostsUsingBatchGet

getPostsUsingBatchGet.request.vtl

#set($posts = [])
#foreach($post in ${ctx.args.posts})
    #set($map = {})
    $util.qr($map.put("PK", $util.dynamodb.toString($post.PK)))
    $util.qr($map.put("SK", $util.dynamodb.toString($post.SK)))
    $util.qr($posts.add($map))
#end


{
    "operation" : "BatchGetItem",
    "tables" : {
        "posts": {
            "keys": $util.toJson($posts),
            "consistentRead": true
        }
    }
}

getPostsUsingBatchGet.response.vtl

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result.data.posts)

The provided request mapping template (getPostsUsingBatchGet.request.vtl) and response mapping template (getPostsUsingBatchGet.response.vtl) for a GraphQL query named getPostsUsingBatchGet. These templates are used in AWS AppSync to map requests to a data source, typically Amazon DynamoDB in this case.

Request Mapping Template (getPostsUsingBatchGet.request.vtl):

This mapping template defines how incoming GraphQL query requests are translated into a format that DynamoDB can understand for a batch get operation. Here’s a detailed explanation:

#set($posts = []): This line initializes an empty array called $posts. This array will hold the list of keys (PK and SK pairs) for the DynamoDB batch get operation.

#foreach($post in ${ctx.args.posts}): This foreach loop iterates through the posts argument provided in the GraphQL request. Each iteration represents a post item that you want to retrieve from DynamoDB.

#set($map = {}): Inside the loop, a new empty map called $map is created to represent the key for each post.

$util.qr($map.put(“PK”, $util.dynamodb.toString($post.PK)): This line sets the “PK” attribute in the $map using the PK attribute of the GraphQL argument post. It converts the value to a string suitable for DynamoDB.

$util.qr($map.put(“SK”, $util.dynamodb.toString($post.SK)): Similarly, this line sets the “SK” attribute in the $map using the SK attribute of the GraphQL argument post.

$util.qr($posts.add($map)): The map for the post is added to the $posts array for batch retrieval.

The resulting $posts array holds all the keys for the items you want to retrieve from DynamoDB.

Finally, the request object for the batch get operation is constructed. It specifies the operation as “BatchGetItem” and provides the tables and consistentRead settings. The keys are the $posts array converted to JSON, and consistentRead is set to true to ensure a consistent read from DynamoDB.

Response Mapping Template (getPostsUsingBatchGet.response.vtl):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

#if($ctx.error): This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.

$util.toJson($ctx.result.data.posts): Assuming there are no errors, this line takes the result returned from DynamoDB (in the ctx.result.data.posts object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL query. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the getPostsUsingBatchGet query facilitate the translation of GraphQL requests and responses to and from DynamoDB for batch retrieval operations. They ensure that the query is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format. This allows for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment, particularly for retrieving multiple items from DynamoDB in a single batch request.

batchPutItem:createPostsUsingBatchPut

createPostsUsingBatchPut.request.vtl:

#set($postsdata = [])
#foreach($item in ${ctx.args.posts})
    $util.qr($postsdata.add($util.dynamodb.toMapValues($item)))
#end


{
    "operation" : "BatchPutItem",
    "tables" : {
        "posts": $utils.toJson($postsdata)
    }
}

createPostsUsingBatchPut.response.vtl:

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

batchDeleteItem:deletePostsUsingBatchDelete

deletePostsUsingBatchDelete.request.vtl

#set($posts = [])
#foreach($post in ${ctx.args.posts})
    #set($map = {})
    $util.qr($map.put("PK", $util.dynamodb.toString($post.PK)))
    $util.qr($map.put("SK", $util.dynamodb.toString($post.SK)))
    $util.qr($ids.add($map))
#end


{
    "operation" : "BatchDeleteItem",
    "tables" : {
        "posts": $util.toJson($posts)
    }
}

deletePostsUsingBatchDelete.response.vtl

## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## Pass back the result from DynamoDB. 
$util.toJson($ctx.result)

The provided request mapping template (deletePostsUsingBatchDelete.request.vtl) and response mapping template (deletePostsUsingBatchDelete.response.vtl) for a GraphQL mutation named deletePostsUsingBatchDelete. These templates are used in AWS AppSync to map requests to a data source, typically Amazon DynamoDB in this case.

Request Mapping Template (deletePostsUsingBatchDelete.request.vtl):

This mapping template defines how incoming GraphQL mutation requests are translated into a format that DynamoDB can understand for a batch delete operation. Here’s a detailed explanation:

#set($posts = []): This line initializes an empty array called $posts. This array will hold the list of keys (PK and SK pairs) for the DynamoDB batch delete operation.

#foreach($post in ${ctx.args.posts}): This foreach loop iterates through the posts argument provided in the GraphQL request. Each iteration represents a post item that you want to delete from DynamoDB.

#set($map = {}): Inside the loop, a new empty map called $map is created to represent the key for each post.

$util.qr($map.put(“PK”, $util.dynamodb.toString($post.PK)): This line sets the “PK” attribute in the $map using the PK attribute of the GraphQL argument post. It converts the value to a string suitable for DynamoDB.

$util.qr($map.put(“SK”, $util.dynamodb.toString($post.SK)): Similarly, this line sets the “SK” attribute in the $map using the SK attribute of the GraphQL argument post.

$util.qr($posts.add($map)): The map for the post is added to the $posts array for batch deletion.

The resulting $posts array holds all the keys for the items you want to delete from DynamoDB.

Finally, the request object for the batch delete operation is constructed. It specifies the operation as “BatchDeleteItem” and provides the tables setting. The tables object contains the “posts” table and the list of items to be deleted from it.

Response Mapping Template (deletePostsUsingBatchDelete.response.vtl):

This mapping template specifies how the response from the data source (DynamoDB) is translated into a format suitable for a GraphQL response. Here’s a detailed explanation:

#if($ctx.error): This conditional statement checks if there’s an error in the response from the data source. If an error is detected, it is handled by raising a GraphQL field error using $util.error(). The error message and type are taken from the ctx.error object.

$util.toJson($ctx.result): Assuming there are no errors, this line takes the result returned from DynamoDB (in the ctx.result object) and converts it into a JSON format. This JSON data is what will be included in the response to the GraphQL mutation. It ensures that the response is in a format that the GraphQL client can understand.

In summary, these mapping templates for the deletePostsUsingBatchDelete mutation facilitate the translation of GraphQL requests and responses to and from DynamoDB for batch deletion operations. They ensure that the mutation is correctly formatted and that the data source’s response is transformed into a GraphQL-friendly format. This allows for seamless integration between GraphQL and DynamoDB within the AWS AppSync environment, particularly for removing multiple items from DynamoDB in a single batch request.

AppSync JS DynamoDB Operations

Query:listPosts

listPosts.js

import { util } from "@aws-appsync/utils";


/
 * Queries a DynamoDB table for items based on the `id`
 * @param {import('@aws-appsync/utils').Context<{id: string}>} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBQueryRequest} the request
 */
export function request(ctx) {
  return {
    operation: "Query",
    query: {
      expression: "#PK = :PK and #SK = :SK",
      expressionNames: util.dynamodb.toMapValues({ "#PK": "PK" ,"#SK" : "SK"}),
      expressionValues: util.dynamodb.toMapValues({ ":PK": ctx.args.PK,":SK": ctx.args.SK }),
    },
  };
}


/
 * Returns the query items
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {[*]} a flat list of result items
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.items;
}

The provided code, which appears to be using the AWS AppSync JavaScript utility library to query a DynamoDB table based on a specific `id`. This code consists of two parts: a request mapping function and a response mapping function.

Request Mapping Function (`request`):

This function prepares the request that will be sent to the DynamoDB table for querying data. Here’s a detailed explanation of each part of the request mapping function:

– `operation: “Query”`: This specifies the operation to be performed on the DynamoDB table, which is a query in this case.
– `query`: This is an object that specifies the query expression, expression names, and expression values. It contains the following elements:
– `expression`: This is the query expression, which is defined as `#PK = :PK and #SK = :SK`. It uses placeholders for attribute names and values, which are later substituted with actual values using expression names and expression values.
       – `expressionNames`: This is an object that maps placeholder names (e.g., `#PK`, `#SK`) to their corresponding attribute names (`PK`, `SK`). This is necessary because DynamoDB requires attribute names to be                 represented  using placeholders in query expressions.
      – `expressionValues`: This is an object that maps placeholder values (e.g., `:PK`, `:SK`) to their actual values, which are extracted from the `ctx.args` object. These values are provided by the GraphQL query when it’s executed.

Response Mapping Function (`response`):

This function handles the response from the DynamoDB query and prepares the data to be returned to the client. Here’s a detailed explanation:

– `if (ctx.error) { … }`: This conditional statement checks if there is an error in the response context (`ctx`). If an error is detected, it uses the `util.error` function to raise a GraphQL field error. The error message and type are extracted from the `ctx.error` object.

– `return ctx.result.items`: Assuming there are no errors, this line extracts the list of items from the `ctx.result` object. These items are the results of the DynamoDB query and will be returned to the client. The response is typically an array of items.

In summary, this code provides a structured way to query a DynamoDB table using AWS AppSync. It specifies the query operation, query expression, expression names, and expression values. It also handles any errors that may occur during the query and prepares the result items for response. This code is used as part of an AWS AppSync resolver and allows you to integrate DynamoDB queries into your GraphQL API, making it easier to interact with and retrieve data from DynamoDB tables.

GetItem:getPost

getPost.js:

import { util } from "@aws-appsync/utils";

/
 * Queries a DynamoDB table for items based on the `id`
 * @param {import('@aws-appsync/utils').Context<{id: string}>} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBQueryRequest} the request
 */
export function request(ctx) {
  return {
    operation: "Query",
    query: {
      expression: "#PK = :PK and #SK = :SK",
      expressionNames: util.dynamodb.toMapValues({ "#PK": "PK" ,"#SK" : "SK"}),
      expressionValues: util.dynamodb.toMapValues({ ":PK": ctx.args.PK,":SK": ctx.args.SK }),
    },
  };
}

/
 * Returns the query items
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {[*]} a flat list of result items
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.items;
}

The provided code, which appears to be a pair of functions for retrieving a single item from a DynamoDB table using AWS AppSync. These functions include a request mapping function and a response mapping function.

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB for retrieving an item based on the provided key. Here’s a detailed explanation of each part of the request mapping function:

operation: “GetItem”: This specifies the operation to be performed on the DynamoDB table, which is a “GetItem” operation. It’s used to retrieve a specific item by its primary key (PK) and sort key (SK).
key: This is an object that represents the primary key and sort key of the item you want to retrieve. It’s constructed using the util.dynamodb.toMapValues function and the values provided in the ctx.args object. The ctx.args object typically contains the PK and SK values required to identify the specific item.

Response Mapping Function (response):

This function handles the response from the DynamoDB operation and prepares the data to be returned to the client. Here’s a detailed explanation:

return ctx.result: This line simply returns the result obtained from the DynamoDB operation. This result is typically an object representing the item retrieved from DynamoDB. It includes attributes such as PK, SK, and any other attributes associated with the item.

In summary, this code provides a structured way to retrieve a specific item from a DynamoDB table using AWS AppSync. The request mapping function specifies the “GetItem” operation and the key used to identify the item. The response mapping function then returns the item that was fetched from DynamoDB to the client.

These functions are typically used as part of an AWS AppSync resolver, allowing you to integrate DynamoDB retrieval operations into your GraphQL API and easily fetch specific items from your database in response to client requests.

putItem:createPost

createPost.js:

import { util } from "@aws-appsync/utils";

/**
 * Puts an item into the DynamoDB table using an auto-generated ID.
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBPutItemRequest} the request
 */
ctx.args.createdTime = util.time.nowEpochSeconds()
export function request(ctx) {
  return {
    operation: "PutItem",
    key: util.dynamodb.toMapValues({ PK: util.autoId() ,SK : `posts#${ctx.args.postStatus}` }),
    attributeValues: util.dynamodb.toMapValues(ctx.args),
  };
}

/**
 * Returns the item or throws an error if the operation failed
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the inserted item
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result;
}

The provided code, which appears to be a pair of functions for inserting an item into a DynamoDB table using AWS AppSync. These functions include a request mapping function and a response mapping function.

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB for inserting an item into the table. Here’s a detailed explanation of each part of the request mapping function:

ctx.args.createdTime = util.time.nowEpochSeconds(): This line sets the createdTime attribute in the ctx.args object to the current epoch time in seconds. It appears to be a way to record the time at which the item was created.

operation: “PutItem”: This specifies the operation to be performed on the DynamoDB table, which is a “PutItem” operation. It’s used to insert a new item into the table.
key: This is an object that represents the primary key (PK and SK) for the item to be inserted. It’s constructed using the util.dynamodb.toMapValues function. The PK appears to be generated using util.autoId(), which likely creates a unique identifier for the primary key. The SK is also constructed, including the postStatus attribute.
attributeValues: This is an object that represents the attribute values of the item to be inserted. It’s constructed using the util.dynamodb.toMapValues function, taking the values from the ctx.args object. This means that the attributes and their values come from the GraphQL query or mutation arguments.

Response Mapping Function (response):

This function handles the response from the DynamoDB operation and prepares the data to be returned to the client. Here’s a detailed explanation:

if (ctx.error) { … }: This conditional statement checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message and type are extracted from the ctx.error object.

return ctx.result: Assuming there are no errors, this line simply returns the result obtained from the DynamoDB operation. This result is typically an object representing the item that was inserted into DynamoDB. It includes attributes such as PK, SK, and any other attributes that were part of the insertion.

In summary, this code provides a structured way to insert an item into a DynamoDB table using AWS AppSync. It specifies the “PutItem” operation, the primary key, and the attribute values of the item. It also handles any errors that may occur during the insertion and prepares the inserted item for response. These functions are typically used as part of an AWS AppSync resolver, allowing you to integrate DynamoDB insert operations into your GraphQL API and easily add new items to your database in response to client requests.

updateItem:updatePost

updatePost.js:

import { util } from "@aws-appsync/utils";
export function request(ctx) {
  const {
    args: {
       PK, SK, ...items
    },
  } = ctx;
  items.modifiedTime = util.time.nowEpochSeconds();
 
  const condition = {
    id: { attributeExists: true },
    version: { eq: items.expectedVersion },
  };
  items.expectedVersion += 1;
  return dynamodbUpdateRequest({
    keys: { PK: ctx.args.PK, SK: ctx.args.SK },
    items,
    condition,
  });
}

function dynamodbUpdateRequest(params) {
  const { keys, items } = params;

  const sets = [];
  const removes = [];
  const expressionNames = {};
  const expValues = {};

  // Iterate through the keys of the values
  for (const [key, item] of Object.entries(items)) {
    expressionNames[`#${key}`] = key;
    if (item) {
      sets.push(`#${key} = :${key}`);
      expValues[`:${key}`] = item;
    } else {
      removes.push(`#${key}`);
    }
  }

  let expression = sets.length ? `SET ${sets.join(", ")}` : "";
  expression += removes.length ? ` REMOVE ${removes.join(", ")}` : "";
  return {
    operation: "UpdateItem",
    key: util.dynamodb.toMapValues(keys),
    update: {
      expression,
      expressionNames,
      expressionValues: util.dynamodb.toMapValues(expValues),
    },
  };
}
export function response(ctx) {
  const { result, error } = ctx;
  if (error) {
    util.error(error.message, error.type, result);
  }
  return ctx.result;
}

The provided code, which appears to be a pair of functions for updating an item in a DynamoDB table using AWS AppSync. These functions include a request mapping function (request) and a response mapping function (response).

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB for updating an item in the table. Here’s a detailed explanation of each part of the request mapping function:

The function starts by extracting relevant values from the ctx (context) object. It specifically retrieves PK, SK, and the rest of the attributes (items) that need to be updated. The PK and SK are used to identify the specific item to be updated.

items.modifiedTime = util.time.nowEpochSeconds();: This line adds or updates the modifiedTime attribute in the items object with the current epoch time in seconds. This is a way to record the time of the update.

const condition: This is an object that specifies the conditions that must be met for the update to proceed. In this case, it checks if the id attribute exists and if the version matches the expectedVersion. The expectedVersion is incremented to prepare for the next version.

The dynamodbUpdateRequest function is then called to construct the update request. It takes the keys (PK and SK), the items to be updated, and the condition as parameters. This function generates the necessary DynamoDB update request based on these inputs.

dynamodbUpdateRequest Function:

This function takes the parameters and constructs a DynamoDB update request. Here’s a detailed explanation of each part of this function:

It initializes arrays sets and removes to keep track of attributes to be updated (SET) and removed (REMOVE), respectively. It also initializes objects expressionNames and expValues to store the expression names and values.

The function iterates through the keys and values in the items object. For each key-value pair, it does the following:

Adds an entry in expressionNames to define the expression name for the attribute.

If the value is not null or undefined (meaning an update is required), it adds a set expression for the attribute in the form #key = :key, and the corresponding expression value is added to expValues.

If the value is null or undefined (meaning the attribute should be removed), it adds the attribute name to the removes array.

It constructs the update expression, incorporating both the sets (SET) and removes (REMOVE) sections based on the attributes to be updated and removed.

The function returns an object that represents the DynamoDB update request, including the operation, key, and update sections. This object is used to perform the update in DynamoDB.

Response Mapping Function (response):

This function handles the response from the DynamoDB operation and prepares the data to be returned to the client. Here’s a detailed explanation:

It checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message, error type, and result (if available) are included in the error response.

Assuming there are no errors, this function simply returns the result obtained from the DynamoDB operation. The result typically represents the updated item in DynamoDB.

In summary, this code provides a structured way to update an item in a DynamoDB table using AWS AppSync. It allows for partial updates of attributes, removing attributes, and incrementing a version attribute to ensure data consistency. The request mapping function constructs the update request, and the response mapping function handles potential errors and prepares the response. These functions are typically used as part of an AWS AppSync resolver to integrate DynamoDB update operations into your GraphQL API.

deleteItem:deletePost

deletePost.js

import { util } from "@aws-appsync/utils";

/**
 * Deletes an item with id `ctx.args.id` from the DynamoDB table
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBDeleteItemRequest} the request
 */
export function request(ctx) {
  return {
    operation: "DeleteItem",
    key: util.dynamodb.toMapValues({ PK: ctx.args.PK, SK :ctx.args.SK }),
  };
}

/**
 * Returns the deleted item. Throws an error if the operation failed
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the deleted item
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result;
}

The provided code, which appears to be a pair of functions for deleting an item from a DynamoDB table using AWS AppSync. These functions include a request mapping function and a response mapping function.

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB for deleting an item from the table. Here’s a detailed explanation of each part of the request mapping function:

operation: “DeleteItem”: This specifies the operation to be performed on the DynamoDB table, which is a “DeleteItem” operation. It’s used to delete a specific item based on its primary key (PK) and sort key (SK).
key: This is an object that represents the primary key and sort key of the item to be deleted. It’s constructed using the util.dynamodb.toMapValues function and the values provided in the ctx.args object. The ctx.args object typically contains the PK and SK values required to identify the specific item to be deleted.

Response Mapping Function (response):

This function handles the response from the DynamoDB operation and prepares the data to be returned to the client. Here’s a detailed explanation:

if (ctx.error) { … }: This conditional statement checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message and type are extracted from the ctx.error object.

return ctx.result: Assuming there are no errors, this line simply returns the result obtained from the DynamoDB operation. In the context of a “DeleteItem” operation, the result is often null or undefined because the item is deleted from the database. The response doesn’t typically include the deleted item.
In summary, this code provides a structured way to delete a specific item from a DynamoDB table using AWS AppSync. The request mapping function specifies the “DeleteItem” operation and the key used to identify the item. The response mapping function then returns null or undefined to indicate the successful deletion. If there is an error, it raises a GraphQL field error to provide an appropriate error message to the client.

These functions are typically used as part of an AWS AppSync resolver, allowing you to integrate DynamoDB deletion operations into your GraphQL API and easily remove items from your database in response to client requests.

batchGetItem : getPostsUsingBatchGet

getPostsUsingBatchGet.js

import { util } from '@aws-appsync/utils';
export function request(ctx) {
    let ids = []
    for (const post of ctx.args.posts) {
        let obj = {
            PK: post.PK,
            SK: post.SK,
        }
        let mapValue = util.dynamodb.toMapValues(obj)
        ids.push(mapValue)
    }
    return {
        operation: 'BatchGetItem',
        tables: {
            posts: {
                keys: ids,
                consistentRead: false
            }
        },
    }
}
export function response(ctx) {
    if (ctx.error) {
        util.error(ctx.error.message, ctx.error.type);
    }
    return ctx.result.data.posts;
}

The provided code for getPostsUsingBatchGet.js, which appears to be a pair of functions for batch retrieving items from a DynamoDB table using AWS AppSync. These functions include a request mapping function (request) and a response mapping function (response).

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB to batch retrieve items from the table. Here’s a detailed explanation of each part of the request mapping function:

let ids = []: This line initializes an empty array called ids to store the keys of the items you want to retrieve.

The function uses a for…of loop to iterate through the ctx.args.posts array. This array likely contains multiple posts that need to be retrieved.

For each post in ctx.args.posts, the function creates an object obj with PK (Partition Key) and SK (Sort Key) attributes. These attributes are necessary to uniquely identify the items you want to retrieve.

The obj is then converted into a DynamoDB map value using util.dynamodb.toMapValues(obj). This ensures that the keys are in the correct format for DynamoDB.

The DynamoDB map value is added to the ids array, which will contain all the keys for the items to be retrieved.

Finally, the function returns an object representing the batch get request. It specifies the operation as ‘BatchGetItem’, defines the target table (‘posts’ in this case), and provides the keys array. The consistentRead flag is set to false, meaning that the retrieval doesn’t require strong consistency.

Response Mapping Function (response):

This function handles the response from the DynamoDB batch get operation and prepares the data to be returned to the client. Here’s a detailed explanation:

It first checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message and error type are included in the error response.

Assuming there are no errors, this function returns the data.posts array from the response context. This array likely contains the retrieved items from DynamoDB.

In summary, this code provides a structured way to batch retrieve items from a DynamoDB table using AWS AppSync. The request mapping function constructs the batch get request by iterating through a list of keys, and the response mapping function handles potential errors and prepares the response. These functions are typically used as part of an AWS AppSync resolver to integrate DynamoDB batch retrieval operations into your GraphQL API.

batchPutItem:createPostsUsingBatchPut

createPostsUsingBatchPut.js:

import { util } from "@aws-appsync/utils";

/**
 * Gets items from the DynamoDB tables in batches with the provided `id`` keys
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBBatchPutItemRequest} the request
 */
export function request(ctx) {
  return {
    operation: "BatchPutItem",
    tables: {
      posts: ctx.args.posts.map((post) => util.dynamodb.toMapValues(post)),
    },
  };
}

/**
 * Returns the BatchPutItem table results
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {[*]} the items
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.data.posts;
}

The provided code for createPostsUsingBatchPut.js, which appears to be a pair of functions for batch putting items into a DynamoDB table using AWS AppSync. These functions include a request mapping function (request) and a response mapping function (response).

Request Mapping Function (request):

This function prepares the request that will be sent to DynamoDB to batch put items into the table. Here’s a detailed explanation of each part of the request mapping function:

The function returns an object with the operation set to “BatchPutItem.” This specifies that a batch put operation will be performed in DynamoDB.

The tables object is defined, and it contains a single entry with the key “Posts.” The value of this entry is an array generated using ctx.args.posts.map(…). This implies that you are performing a batch put operation on the “Posts” table and are providing an array of items to be inserted.

Inside the map function, for each post in ctx.args.posts, it uses util.dynamodb.toMapValues(post) to convert the post object into a format suitable for DynamoDB.

In summary, this code constructs a request for a batch put operation in DynamoDB. It specifies the target table (“Posts”) and provides an array of items to be inserted.

Response Mapping Function (response):

This function handles the response from the DynamoDB batch put operation and prepares the data to be returned to the client. Here’s a detailed explanation:

It first checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message and error type are included in the error response.

Assuming there are no errors, this function returns the data.Posts array from the response context. This array likely contains information about the items that were successfully inserted into DynamoDB as a result of the batch put operation.

In summary, this code provides a structured way to perform a batch put operation in DynamoDB using AWS AppSync. The request mapping function constructs the batch put request, and the response mapping function handles potential errors and prepares the response. These functions are typically used as part of an AWS AppSync resolver to integrate DynamoDB batch insert operations into your GraphQL API.

batchDeleteItem:deletePostsUsingBatchDelete

deletePostsUsingBatchDelete.js:

import { util } from "@aws-appsync/utils";

/**
 * Deletes items from DynamoDB tables in batches with the provided `PK` and `SK` keys
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {import('@aws-appsync/utils').DynamoDBBatchDeleteItemRequest} the request
 */
export function request(ctx) {
  return {
    operation: "BatchDeleteItem",
    tables: {
      posts: ctx.args.items.map((item) => util.dynamodb.toMapValues(item)),
    },
  };
}

/**
 * Returns the BatchDeleteItem table results
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {[*]} the items
 */
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.data.posts;
}

The provided code is for handling batch deletion of items from DynamoDB tables using AWS AppSync. It consists of two functions: the request mapping function (request) and the response mapping function (response). Let’s break down each of these functions:

Request Mapping Function (request):

This function prepares the request for batch item deletion and returns it. Here’s a detailed explanation of each part of the request mapping function:

operation: “BatchDeleteItem”: This specifies the operation type as a batch item deletion.
tables: This is an object containing information about the tables from which items should be deleted. In this case, the target table is “posts,” which is assumed to be the DynamoDB table you want to delete items from.

Inside the “tables” object, it uses ctx.args.items.map(…) to iterate through an array of items specified in the request context (ctx.args.items). For each item, it uses util.dynamodb.toMapValues(item) to convert the item into a format suitable for DynamoDB. This format includes the PK (Partition Key) and SK (Sort Key) values.

The result is an object that represents the batch delete request. It includes the operation type and an array of items to be deleted.

Response Mapping Function (response):

This function handles the response from the batch delete operation and prepares the data to be returned to the client. Here’s a detailed explanation:

It first checks if there is an error in the response context (ctx). If an error is detected, it uses the util.error function to raise a GraphQL field error. The error message and error type are included in the error response.

Assuming there are no errors, this function returns ctx.result.data.posts. This likely contains the results of the batch delete operation. The exact structure of this data may vary depending on the AWS AppSync configuration and the structure of the data being deleted.

In summary, this code is designed to perform batch item deletion from a DynamoDB table (in this case, the “posts” table) using AWS AppSync. The request mapping function constructs the batch delete request, and the response mapping function handles potential errors and prepares the response data. These functions are typically used as part of an AWS AppSync resolver to integrate DynamoDB batch deletion operations into your GraphQL API.