AWS AppSync
AWS AppSync Developer Guide

Resolver Mapping Template Reference for DynamoDB

The AWS AppSyncDynamoDB resolver enables you to use GraphQL to store and retrieve data in existing Amazon DynamoDB tables in your account. This resolver works by enabling you to map an incoming GraphQL request into a DynamoDB call, and then map the DynamoDB response back to GraphQL. This section describes the mapping templates for supported DynamoDB operations.

GetItem

The GetItem request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make a GetItem request to DynamoDB, and allows you to specify:

  • The key of the item in DynamoDB

  • Whether to use a consistent read or not

The GetItem mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "foo" : ... typed value, "bar" : ... typed value }, "consistentRead" : true }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the GetItemDynamoDB operation, this must be set to GetItem. This value is required.

key

The key of the item in DynamoDB. DynamoDB items may have a single hash key, or a hash key and sort key, depending on the table structure. For more information on how to specify a "typed value", see Type System (Request Mapping). This value is required.

consistentRead

Whether or not to perform a strongly consistent read with DynamoDB. This is optional, and defaults to false.

The item returned from DynamoDB is automatically converted into GraphQL and JSON primitive types, and is available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

Example

Following is a mapping template for a GraphQL query getThing(foo: String!, bar: String!):

{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "foo" : { "S" : "${context.arguments.foo}" }, "bar" : { "S" : "${context.arguments.bar}" } }, "consistentRead" : true }

See the DynamoDB API documentation for more information about the DynamoDBGetItem API.

PutItem

The PutItem request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make a PutItem request to DynamoDB, and allows you to specify the following:

  • The key of the item in DynamoDB

  • The full contents of the item (composed of key and attributeValues)

  • Conditions for the operation to succeed

The PutItem mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "PutItem", "key": { "foo" : ... typed value, "bar" : ... typed value }, "attributeValues" : { "baz" : ... typed value }, "condition" : { ... } }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the PutItemDynamoDB operation, this must be set to PutItem. This value is required.

key

The key of the item in DynamoDB. DynamoDB items may have a single hash key, or a hash key and sort key, depending on the table structure. For more information on how to specify a "typed value", see Type System (Request Mapping). This value is required.

attributeValues

The rest of the attributes of the item to be put into DynamoDB. For more information on how to specify a "typed value", see Type System (Request Mapping). This field is optional.

condition

A condition to determine if the request should succeed or not, based on the state of the object already in DynamoDB. If no condition is specified, the PutItem request will overwrite any existing entry for that item. For more information on conditions, see Condition Expressions. This value is optional.

The item written to DynamoDB is automatically converted into GraphQL and JSON primitive types and is available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

Example 1

Following is a mapping template for a GraphQL mutation updateThing(foo: String!, bar: String!, name: String!, version: Int!).

If no item with the specified key exists, it will be created. If an item already exists with the specified key, it will be overwritten.

{ "version" : "2017-02-28", "operation" : "PutItem", "key": { "foo" : { "S" : "${context.arguments.foo}" }, "bar" : { "S" : "${context.arguments.bar}" } }, "attributeValues" : { "name" : { "S" : "${context.arguments.name}" }, "version" : { "N" : ${context.arguments.version} } } }

Example 2

Following is a mapping template for a GraphQL mutation updateThing(foo: String!, bar: String!, name: String!, expectedVersion: Int!).

This example checks to be sure the item currently in DynamoDB has the version field set to expectedVersion.

{ "version" : "2017-02-28", "operation" : "PutItem", "key": { "foo" : { "S" : "${context.arguments.foo}" }, "bar" : { "S" : "${context.arguments.bar}" } }, "attributeValues" : { "name" : { "S" : "${context.arguments.name}" }, #set( $newVersion = $context.arguments.expectedVersion + 1 ) "version" : { "N" : ${newVersion} } }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : ${context.arguments.expectedVersion} } } } }

See the DynamoDB API documentation for more information about the DynamoDBPutItem API.

UpdateItem

The UpdateItem request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make an UpdateItem request to DynamoDB, and allows you to specify the following:

  • The key of the item in DynamoDB

  • An update expression describing how to update the item in DynamoDB

  • Conditions for the operation to succeed

The UpdateItem mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "UpdateItem", "key": { "foo" : ... typed value, "bar" : ... typed value }, "update" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value } }, "condition" : { ... } }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the UpdateItemDynamoDB operation, this must be set to UpdateItem. This value is required.

key

The key of the item in DynamoDB. DynamoDB items may have a single hash key, or a hash key and sort key, depending on the table structure. For more information on how to specify a "typed value", see Type System (Request Mapping). This value is required.

update

The update section lets you specify an update expression that describes how to update the item in DynamoDB. See the DynamoDB UpdateExpressions documentation for more information on how to write update expressions. This section is required.

The update section has three components:

expression

The update expression. This value is required.

expressionNames

The substitutions for expression attribute name placeholders, in the form of key-value pairs. The key corresponds to a name placeholder used in the expression, and the value must be a string corresponding to the attribute name of the item in DynamoDB. This field is optional, and should only be populated with substitutions for expression attribute name placeholders used in the expression.

expressionValues

The substitutions for expression attribute value placeholders, in the form of key-value pairs. The key corresponds to a value placeholder used in the expression, and the value must be a typed value. For more information on how to specify a "typed value", see Type System (Request Mapping). This must be specified. This field is optional, and should only be populated with substitutions for expression attribute value placeholders used in the expression.

condition

A condition to determine if the request should succeed or not, based on the state of the object already in DynamoDB. If no condition is specified, the UpdateItem request will update any existing entry regardless of its current state. For more information on conditions, see Condition Expressions. This value is optional.

The item updated in DynamoDB is automatically converted into GraphQL and JSON primitive types and is available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

Example 1

Following is a mapping template for the GraphQL mutation upvote(id: ID!).

In this example, an item in DynamoDB has its upvotes and version fields incremented by 1.

{ "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : { "S" : "${context.arguments.id}" } }, "update" : { "expression" : "ADD #votefield :plusOne, version :plusOne", "expressionNames" : { "#votefield" : "upvotes" }, "expressionValues" : { ":plusOne" : { "N" : 1 } } } }

Example 2

Following is a mapping template for a GraphQL mutation updateItem(id: ID!, title: String, author: String, expectedVersion: Int!).

This is a complex example that inspects the arguments and dynamically generates the update expression that only includes the arguments that have been provided by the client. For example, if title and author are omitted, they are not updated. If an argument is specified but its value is null, then that field is deleted from the object in DynamoDB. Finally, the operation has a condition, which checks to be sure the item currently in DynamoDB has the version field set to expectedVersion:

{ "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 = [] ) ## Increment "version" by 1 ** $!{expAdd.put("version", ":newVersion")} $!{expValues.put(":newVersion", { "N" : 1 })} ## Iterate through each argument, skipping "id" and "expectedVersion" ** #foreach( $entry in $context.arguments.entrySet() ) #if( $entry.key != "id" && $entry.key != "expectedVersion" ) #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")} #if( $entry.key == "ups" || $entry.key == "downs" ) $!{expValues.put(":${entry.key}", { "N" : $entry.value })} #else $!{expValues.put(":${entry.key}", { "S" : "${entry.value}" })} #end #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 }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : ${context.arguments.expectedVersion} } } } }

See the DynamoDB API documentation for more information about the DynamoDBUpdateItem API.

DeleteItem

The DeleteItem request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make a DeleteItem request to DynamoDB, and allows you to specify the following:

  • The key of the item in DynamoDB

  • Conditions for the operation to succeed

The DeleteItem mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "DeleteItem", "key": { "foo" : ... typed value, "bar" : ... typed value }, "condition" : { ... } }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the DeleteItemDynamoDB operation, this must be set to DeleteItem. This value is required.

key

The key of the item in DynamoDB. DynamoDB items may have a single hash key, or a hash key and sort key, depending on the table structure. For more information on how to specify a "typed value", see Type System (Request Mapping). This value is required.

condition

A condition to determine if the request should succeed or not, based on the state of the object already in DynamoDB. If no condition is specified, the DeleteItem request will delete an item regardless of its current state. For more information on conditions, see Condition Expressions. This value is optional.

The item deleted from DynamoDB is automatically converted into GraphQL and JSON primitive types and is available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

Example 1

Following is a mapping template for a GraphQL mutation deleteItem(id: ID!). If an item exists with this ID, it will be deleted.

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

Example 2

Following is a mapping template for a GraphQL mutation deleteItem(id: ID!, expectedVersion: Int!). If an item exists with this ID, it will be deleted, but only if its version field set to expectedVersion:

{ "version" : "2017-02-28", "operation" : "DeleteItem", "key" : { "id" : { "S" : "${context.arguments.id}" } }, "condition" : { "expression" : "attribute_not_exists(id) OR version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : ${context.arguments.expectedVersion} } } } }

See the DynamoDB API documentation for more information about the DynamoDBDeleteItem API.

Query

The Query request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make a Query request to DynamoDB, and allows you to specify the following:

  • Key expression

  • Which index to use

  • Any additional filter

  • How many items to return

  • Whether to use consistent reads

  • query direction (forward or backward)

  • Pagination token

The Query mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "Query", "query" : { "expression" : "some expression", "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value } } "index" : "fooIndex", "nextToken" : "a pagination token", "limit" : 10, "scanIndexForward" : true, "consistentRead" : false, "select" : "ALL_ATTRIBUTES", "filter" : { ... } }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the QueryDynamoDB operation, this must be set to Query. This value is required.

query

The query section lets you specify a key condition expression that describes which items to retrieve from DynamoDB. See the DynamoDB KeyConditions documentation for more information on how to write key condition expressions. This section must be specified.

expression

The query expression. This field must be specified.

expressionNames

The substitutions for expression attribute name placeholders, in the form of key-value pairs. The key corresponds to a name placeholder used in the expression, and the value must be a string corresponding to the attribute name of the item in DynamoDB. This field is optional, and should only be populated with substitutions for expression attribute name placeholders used in the expression.

expressionValues

The substitutions for expression attribute value placeholders, in the form of key-value pairs. The key corresponds to a value placeholder used in the expression, and the value must be a typed value. For more information on how to specify a "typed value", see Type System (Request Mapping). This value is required. This field is optional, and should only be populated with substitutions for expression attribute value placeholders used in the expression.

filter

An additional filter that can be used to filter the results from DynamoDB before they are returned. For more information on filters, see Filters. This field is optional.

index

The name of the index to query. The DynamoDB query operation allows you to scan on Local Secondary Indexes and Global Secondary Indexes in addition to the primary key index for a hash key. If specified, this will tell DynamoDB to query the specified index. If omitted, the primary key index will be queried.

nextToken

The pagination token to continue a previous query. This would have been obtained from a previous query. This field is optional.

limit

The maximum number of items to evaluate (not necessarily the number of matching items). This field is optional.

scanIndexForward

A boolean indicating whether to query forwards or backwards. This field is optional, and defaults to true.

consistentRead

A boolean indicating whether to use consistent reads when querying DynamoDB. This field is optional, and defaults to false.

select

By default, the AWS AppSyncDynamoDB resolver will only return whatever attributes are projected into the index. If more attributes are required, then this field can be set. This field is optional. The supported values are:

ALL_ATTRIBUTES

Returns all of the item attributes from the specified table or index. If you query a local secondary index, then for each matching item in the index DynamoDB will fetch the entire item from the parent table. If the index is configured to project all item attributes, all of the data can be obtained from the local secondary index, and no fetching is required.

ALL_PROJECTED_ATTRIBUTES

Allowed only when querying an index. Retrieves all attributes that have been projected into the index. If the index is configured to project all attributes, this return value is equivalent to specifying ALL_ATTRIBUTES.

The results from DynamoDB are automatically converted into GraphQL and JSON primitive types and are available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

The results have the following structure:

{ items = [ ... ], nextToken = "a pagination token", scannedCount = 10 }

The fields are defined as follows:

items

A list containing the items returned by the DynamoDB query.

nextToken

If there might be more results, nextToken will contain a pagination token that can be used in another request. Note that AWS AppSync will encrypt and obfuscate the pagination token returned from DynamoDB. This is so data from your tables are not inadvertently leaked to the caller. Also note that these pagination tokens cannot be used across different resolvers.

scannedCount

The number of items that matched the query condition expression, before a filter expression (if present) was applied.

Example

Following is a mapping template for a GraphQL query getPosts(owner: ID!).

In this example, a global secondary index on a table is queried to return all posts owned by the specified ID.

{ "version" : "2017-02-28", "operation" : "Query", "query" : { "expression" : "ownerId = :ownerId", "expressionValues" : { ":ownerId" : { "S" : "${context.arguments.owner}" } } } "index" : "owner-index" }

See the DynamoDB API documentation for more information about the DynamoDB Query API.

Scan

The Scan request mapping document lets you tell the AWS AppSyncDynamoDB resolver to make a Scan request to DynamoDB, and allows you to specify the following:

  • A filter to exclude results

  • Which index to use

  • How many items to return

  • Whether to use consistent reads

  • Pagination token

  • Parallel scans

The Scan mapping document has the following structure:

{ "version" : "2017-02-28", "operation" : "Scan", "index" : "fooIndex", "limit" : 10, "consistentRead" : false, "nextToken" : "aPaginationToken", "totalSegments" : 10, "segment" : 1, "filter" : { ... } }

The fields are defined as follows:

version

The template definition version. Only 2017-02-28 is supported. This value is required.

operation

The DynamoDB operation to perform. To perform the ScanDynamoDB operation, this must be set to Scan. This value is required.

filter

An filter that can be used to filter the results from DynamoDB before they are returned. For more information on filters, see Filters. This field is optional.

index

The name of the index to query. The DynamoDB query operation allows you to scan on Local Secondary Indexes and Global Secondary Indexes in addition to the primary key index for a hash key. If specified, this tells DynamoDB to query the specified index. If omitted, then the primary key index will be queried.

limit

The maximum number of items to evaluate at a single time. This field is optional.

consistentRead

A boolean indicating whether to use consistent reads when querying DynamoDB. This field is optional, and defaults to false.

nextToken

The pagination token to continue a previous query. This would have been obtained from a previous query. This field is optional.

select

By default, the AWS AppSyncDynamoDB resolver will only return whatever attributes are projected into the index. If more attributes are required, then this field can be set. This field is optional. The supported values are:

ALL_ATTRIBUTES

Returns all of the item attributes from the specified table or index. If you query a local secondary index, then for each matching item in the index DynamoDB will fetch the entire item from the parent table. If the index is configured to project all item attributes, then all of the data can be obtained from the local secondary index, and no fetching is required.

ALL_PROJECTED_ATTRIBUTES

Allowed only when querying an index. Retrieves all attributes that have been projected into the index. If the index is configured to project all attributes, this return value is equivalent to specifying ALL_ATTRIBUTES.

totalSegments

The number of segments to partition the table by when performing a parallel scan. This field is optional, but must be specified if segment is specified.

segment

The table segment in this operation when performing a parallel scan. This field is optional, but must be specified if totalSegments is specified.

The results returned by the DynamoDB scan are automatically converted into GraphQL and JSON primitive types and is available in the mapping context ($context.result).

For more information about DynamoDB type conversion, see Type System (Response Mapping).

For more information about response mapping templates, see Resolver Mapping Template Overview.

The results have the following structure:

{ items = [ ... ], nextToken = "a pagination token", scannedCount = 10 }

The fields are defined as follows:

items

A list containing the items returned by the DynamoDB scan.

nextToken

If there might be more results, nextToken will contain a pagination token that can be used in another request. Note that AWS AppSync will encrypt and obfuscate the pagination token returned from DynamoDB. This is so data from your tables are not inadvertently leaked to the caller. Also note that these pagination tokens cannot be used across different resolvers.

scannedCount

The number of items that were retrieved by DynamoDB before a filter expression (if present) was applied.

Example 1

Following is a mapping template for the GraphQL query: allPosts.

In this example, all entries in the table are returned.

{ "version" : "2017-02-28", "operation" : "Scan" }

Example 2

Following is a mapping template for the GraphQL query: postsMatching(title: String!).

In this example, all entries in the table are returned where the title starts with the title argument.

{ "version" : "2017-02-28", "operation" : "Scan", "filter" : { "expression" : "begins_with(title, :title)", "expressionValues" : { ":title" : { "S" : "${context.arguments.title}" } }, } }

See the DynamoDB API documentation for more information about the DynamoDB Scan API.

Type System (Request Mapping)

When using the AWS AppSyncDynamoDB resolver to call your DynamoDB tables, AWS AppSync needs to know the type of each value to use in that call. This is because DynamoDB supports more type primitives than GraphQL or JSON (such as sets and binary data). AWS AppSync needs some hints when translating between GraphQL and DynamoDB, otherwise it would have to make some assumptions on how data is structured in your table.

For more information about DynamoDB data types, see the DynamoDBData Type Descriptors and Data Types documentation.

A DynamoDB value is represented by a JSON object containing a single key-value pair. The key specifies the DynamoDB type, and the value specifies the value itself. In the following example, the key S denotes that the value is a string, and the value identifier is the string value itself.

{ "S" : "identifier" }

Note that the JSON object cannot have more than one key-value pair. If more than one key-value pair is specified, the request mapping document will not be parsed.

A DynamoDB value is used anywhere in a request mapping document where you need to specify a value. Some places where you will need to do this include: key and attributeValue sections, and the expressionValues section of expression sections. In the following example, the DynamoDB String value identifier is being assigned to the id field in a key section (perhaps in a GetItem request mapping document).

"key" : { "id" : { "S" : "identifier" } }

Supported Types

AWS AppSync supports the following DynamoDB scalar, document and set types:

String type S

A single string value. A DynamoDB String value is denoted by:

{ "S" : "some string" }

An example usage is:

"key" : { "id" : { "S" : "some string" } }
String set type SS

A set of string values. A DynamoDB String Set value is denoted by:

{ "SS" : [ "first value", "second value", ... ] }

An example usage is:

"attributeValues" : { "phoneNumbers" : { "SS" : [ "+1 555 123 4567", "+1 555 234 5678" ] } }
Number type N

A single numeric value. A DynamoDB Number value is denoted by:

{ "N" : 1234 }

An example usage is:

"expressionValues" : { ":expectedVersion" : { "N" : 1 } }
Number set type NS

A set of number values. A DynamoDB Number Set value is denoted by:

{ "NS" : [ 1, 2.3, 4 ... ] }

An example usage is:

"attributeValues" : { "sensorReadings" : { "NS" : [ 67.8, 12.2, 70 ] } }
Binary type B

A binary value. A DynamoDB Binary value is denoted by:

{ "B" : "SGVsbG8sIFdvcmxkIQo=" }

Note that the value is actually a string, where the string is the Base64 encoded representation of the binary data. AWS AppSync will decode this string back into its binary value before sending it to DynamoDB. AWS AppSync uses the Base64 decoding scheme as defined by RFC 2045: any character that is not in the Base64 alphabet is ignored.

An example usage is:

"attributeValues" : { "binaryMessage" : { "B" : "SGVsbG8sIFdvcmxkIQo=" } }
Binary set type BS

A set of binary values. A DynamoDB Binary Set value is denoted by:

{ "BS" : [ "SGVsbG8sIFdvcmxkIQo=", "SG93IGFyZSB5b3U/Cg==" ... ] }

Note that the value is actually a string, where the string is the Base64 encoded representation of the binary data. AWS AppSync will decode this string back into its binary value before sending it to DynamoDB. AWS AppSync uses the Base64 decoding scheme as defined by RFC 2045: any character that is not in the Base64 alphabet is ignored.

An example usage is:

"attributeValues" : { "binaryMessages" : { "BS" : [ "SGVsbG8sIFdvcmxkIQo=", "SG93IGFyZSB5b3U/Cg==" ] } }
Boolean type BOOL

A boolean value. A DynamoDB Boolean value is denoted by:

{ "BOOL" : true }

Note that only true and false are valid values.

An example usage is:

"attributeValues" : { "orderComplete" : { "BOOL" : false } }
List type L

A list of any other supported DynamoDB value. A DynamoDB List value is denoted by:

{ "L" : [ ... ] }

Note that the value is a compound value, where the list can contain zero or more of any supported DynamoDB value (including other lists). The list can also contain a mix of different types.

An example usage is:

{ "L" : [ { "S" : "A string value" }, { "N" : 1 }, { "SS" : [ "Another string value", "Even more string values!" ] } ] }
Map type M

Representing an unordered collection of key-value pairs of other supported DynamoDB values. A DynamoDB Map value is denoted by:

{ "M" : { ... } }

Note that a map can contain zero or more key-value pairs. The key must be a string, and the value can be any supported DynamoDB value (including other maps). The map can also contain a mix of different types.

An example usage is:

{ "M" : { "someString" : { "S" : "A string value" }, "someNumber" : { "N" : 1 }, "stringSet" : { "SS" : [ "Another string value", "Even more string values!" ] } } }
Null type NULL

A null value. A DynamoDB Null value is denoted by:

{ "NULL" : null }

An example usage is:

"attributeValues" : { "phoneNumbers" : { "NULL" : null } }

See the DynamoDB documentation for more information on each type.

Type System (Response Mapping)

When receiving a response from DynamoDB, AWS AppSync automatically converts it into GraphQL and JSON primitive types. Each attribute in DynamoDB is decoded and returned in the response mapping context.

For example, if DynamoDB returns the following:

{ "id" : { "S" : "1234" }, "name" : { "S" : "Nadia" }, "age" : { "N" : 25 } }

Then the AWS AppSyncDynamoDB resolver converts it into GraphQL and JSON types as:

{ "id" : "1234", "name" : "Nadia", "age" : 25 }

This section explains how AWS AppSync will convert the following DynamoDB scalar, document and set types:

String type S

A single string value. A DynamoDB String value will be returned simply as a string.

For example, if DynamoDB returned the following DynamoDB String value:

{ "S" : "some string" }

AWS AppSync will convert it to a string:

"some string"
String set type SS

A set of string values. A DynamoDB String Set value will be returned as a list of strings.

For example, if DynamoDB returned the following DynamoDB String Set value:

{ "SS" : [ "first value", "second value", ... ] }

AWS AppSync will convert it to a list of strings:

[ "+1 555 123 4567", "+1 555 234 5678" ]
Number type N

A single numeric value. A DynamoDB Number value will be returned as a number.

For example, if DynamoDB returned the following DynamoDB Number value:

{ "N" : 1234 }

AWS AppSync will convert it to a number:

1234
Number set type NS

A set of number values. A DynamoDB Number Set value will be returned as a list of numbers.

For example, if DynamoDB returned the following DynamoDB Number Set value:

{ "NS" : [ 67.8, 12.2, 70 ] }

AWS AppSync will convert it to a list of numbers:

[ 67.8, 12.2, 70 ]
Binary type B

A binary value. A DynamoDB Binary value will be returned as a string containing the Base64 representation of that value.

For example, if DynamoDB returned the following DynamoDB Binary value:

{ "B" : "SGVsbG8sIFdvcmxkIQo=" }

AWS AppSync will convert it to a string containing the Base64 representation of the value:

"SGVsbG8sIFdvcmxkIQo="

Note that the binary data is encoded in the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.

Binary set type BS

A set of binary values. A DynamoDB Binary Set value will be returned as a list of strings containing the Base64 representation of the values.

For example, if DynamoDB returned the following DynamoDB Binary Set value:

{ "BS" : [ "SGVsbG8sIFdvcmxkIQo=", "SG93IGFyZSB5b3U/Cg==" ... ] }

AWS AppSync will convert it to a list of strings containing the Base64 representation of the values:

[ "SGVsbG8sIFdvcmxkIQo=", "SG93IGFyZSB5b3U/Cg==" ... ]

Note that the binary data is encoded in the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.

Boolean type BOOL

A boolean value. A DynamoDB Boolean value will be returned as a boolean.

For example, if DynamoDB returned the following DynamoDB Boolean value:

{ "BOOL" : true }

AWS AppSync will convert it to a boolean:

true
List type L

A list of any other supported DynamoDB value. A DynamoDB List value will be returned as a list of values, where each inner value is also converted.

For example, if DynamoDB returned the following DynamoDB List value:

{ "L" : [ { "S" : "A string value" }, { "N" : 1 }, { "SS" : [ "Another string value", "Even more string values!" ] } ] }

AWS AppSync will convert it to a list of converted values:

[ "A string value", 1, [ "Another string value", "Even more string values!" ] ]
Map type M

A key/value collection of any other supported DynamoDB value. A DynamoDB Map value will be returned as a JSON object, where each key/value is also converted.

For example, if DynamoDB returned the following DynamoDB Map value:

{ "M" : { "someString" : { "S" : "A string value" }, "someNumber" : { "N" : 1 }, "stringSet" : { "SS" : [ "Another string value", "Even more string values!" ] } } }

AWS AppSync will convert it to a JSON object:

{ "someString" : "A string value", "someNumber" : 1, "stringSet" : [ "Another string value", "Even more string values!" ] }
Null type NULL

A null value.

For example, if DynamoDB returned the following DynamoDB Null value:

{ "NULL" : null }

AWS AppSync will convert it to a null:

null

Filters

When querying objects in DynamoDB using the Query and Scan operations, you can optionally specify a filter that evaluates the results and returns only the desired values.

The filter mapping section of a Query or Scan mapping document has the following structure:

"filter" : { "expression" : "filter expression" "expressionNames" : { "#name" : "name", }, "expressionValues" : { ":value" : ... typed value }, }

The fields are defined as follows:

expression

The query expression. See the DynamoDB QueryFilter and DynamoDB ScanFilter documentation for more information on how to write filter expressions. This field must be specified.

expressionNames

The substitutions for expression attribute name placeholders, in the form of key-value pairs. The key corresponds to a name placeholder used in the expression, and the value must be a string corresponding to the attribute name of the item in DynamoDB. This field is optional, and should only be populated with substitutions for expression attribute name placeholders used in the expression.

expressionValues

The substitutions for expression attribute value placeholders, in the form of key-value pairs. The key corresponds to a value placeholder used in the expression, and the value must be a typed value. For more information on how to specify a "typed value", see Type System (Request Mapping). This must be specified. This field is optional, and should only be populated with substitutions for expression attribute value placeholders used in the expression.

Example

Following is a filter section for a mapping template, where entries retrieved from DynamoDB are only returned if the title starts with the title argument.

"filter" : { "expression" : "begins_with(#title, :title)", "expressionNames" : { "#title" : "title" } "expressionValues" : { ":title" : { "S" : "${context.arguments.title}" } } }

Condition Expressions

When you mutate objects in DynamoDB by using the PutItem, UpdateItem, and DeleteItemDynamoDB operations, you can optionally specify a condition expression that controls whether the request should succeed or not, based on the state of the object already in DynamoDB before the operation is performed.

The AWS AppSyncDynamoDB resolver allows a condition expression to be specified in PutItem, UpdateItem, and DeleteItem request mapping documents, and also a strategy to follow if the condition fails and the object was not updated.

Example 1

The following PutItem mapping document does not have a condition expression, so it will put an item in DynamoDB even if an item with the same key already exists, overwriting the existing item.

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } } }

Example 2

The following PutItem mapping document does have a condition expression that will only let the operation succeed if an item with the same key does not exist in DynamoDB.

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "condition" : { "expression" : "attribute_not_exists(id)" } }

By default, if the condition check fails, then the AWS AppSyncDynamoDB resolver will return an error for the mutation and the current value of the object in DynamoDB in a data field in the error section of the GraphQL response. However, the AWS AppSyncDynamoDB resolver offers some additional features to help developers handle some common edge cases:

  • If AWS AppSyncDynamoDB resolver can determine that the current value in DynamoDB matches the desired result, then it will treat the operation as if it succeeded anyway.

  • Instead of returning an error, you can configure the resolver to invoke a custom Lambda function to decide how the AWS AppSyncDynamoDB resolver should handle the failure.

These will be described in greater detail in the Handling a Condition Check Failure section.

See the DynamoDB ConditionExpressions documentation for more information about DynamoDB conditions expressions.

Specifying a Condition

The PutItem, UpdateItem, and DeleteItem request mapping documents all allow an optional condition section to be specified. If omitted, no condition check is made. If specified, the condition must be true for the operation to succeed.

A condition section has the following structure:

"condition" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value }, "equalsIgnore" : [ "version" ], "consistentRead" : true, "conditionalCheckFailedHandler" : { "strategy" : "Custom", "lambdaArn" : "arn:..." } }

The following fields specify the condition:

expression

The update expression itself. See the DynamoDB ConditionExpressions documentation for more information about how to write condition expressions. This field must be specified.

expressionNames

The substitutions for expression attribute name placeholders, in the form of key-value pairs. The key corresponds to a name placeholder used in the expression, and the value must be a string corresponding to the attribute name of the item in DynamoDB. This field is optional, and should only be populated with substitutions for expression attribute name placeholders used in the expression.

expressionValues

The substitutions for expression attribute value placeholders, in the form of key-value pairs. The key corresponds to a value placeholder used in the expression, and the value must be a typed value. For more information on how to specify a "typed value", see Type System (request mapping). This must be specified. This field is optional, and should only be populated with substitutions for expression attribute value placeholders used in the expression.

The remaining fields tell the AWS AppSyncDynamoDB resolver how to handle a condition check failure:

equalsIgnore

When a condition check fails when using the PutItem operation, the AWS AppSyncDynamoDB resolver will compare the item currently in DynamoDB against the item it tried to write. If they are the same, then it will treat the operation as it if succeeded anyway. You can use the equalsIgnore field to specify a list of attributes that AWS AppSync should ignore when performing that comparison. For example, if the only difference was a version attribute, then treat the operation as it if succeeded. This field is optional.

consistentRead

When a condition check fails, AWS AppSync will get the current value of the item from DynamoDB using a strongly consistent read. You can use this field to tell the AWS AppSyncDynamoDB resolver to use an eventually consistent read instead. This field is optional, and defaults to true.

conditionalCheckFailedHandler

This section allows you to specify how the AWS AppSyncDynamoDB resolver will treat a condition check failure after it has compared the current value in DynamoDB against the expected result. This section is optional. If omitted, it defaults to a strategy of Reject.

strategy

The strategy the AWS AppSyncDynamoDB resolver will take after it has compared the current value in DynamoDB against the expected result. This field is required, and has two possible values:

Reject

The mutation will fail, and an error for the mutation and the current value of the object in DynamoDB in a data field in the error section of the GraphQL response.

Custom

The AWS AppSyncDynamoDB resolver will invoke a custom Lambda function to decide how to handle the condition check failure. When the strategy is set to Custom, the lambdaArn field must contain the ARN of the Lambda function to invoke.

lambdaArn

The ARN of the Lambda function to invoke to decide how the AWS AppSyncDynamoDB resolver should handle the condition check failure. This field must only be specified when strategy is set to Custom. See Handling a Condition Check Failure for more information about how to use this feature.

Handling a Condition Check Failure

By default, when a condition check fails, the AWS AppSyncDynamoDB resolver will return an error for the mutation and the current value of the object in DynamoDB in a data field in the error section of the GraphQL response. However, the AWS AppSyncDynamoDB resolver offers some additional features to help developers handle some common edge cases:

  • If AWS AppSyncDynamoDB resolver can determine that the current value in DynamoDB matches the desired result, then it will treat the operation as if it succeeded anyway.

  • Instead of returning an error, you can configure the resolver to invoke a custom Lambda function to decide how the AWS AppSyncDynamoDB resolver should handle the failure.

The flowchart for this process is:

Checking for the Desired Result

When the condition check fails, the AWS AppSyncDynamoDB resolver will perform a GetItemDynamoDB request to get the current value of the item from DynamoDB. By default, it will use a strongly consistent read, however this can be configured using the consistentRead field in the condition block and compare it against the expected result:

  • For the PutItem operation, the AWS AppSyncDynamoDB resolver will compare the current value against the one it attempted to write, excluding any attributes listed in equalsIgnore from the comparison. If the items are the same, then it will treat the operation as successful and return the item that was retrieved from DynamoDB. Otherwise, it will then follow the configured strategy.

    For example, if the PutItem request mapping document looked like this:

    { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "attributeValues" : { "name" : { "S" : "Steve" }, "version" : { "N" : 2 } }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : 1 } }, "equalsIgnore": [ "version" ] } }

    And the item currently in DynamoDB looked like this:

    { "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }

    Then the AWS AppSyncDynamoDB resolver would compare the item it tried to write against the current value, see that the only difference was the version field, but because it's configured to ignore the version field, it treats the operation as successful and returns the item that was retrieved from DynamoDB.

  • For the DeleteItem operation, the AWS AppSyncDynamoDB resolver will see if an item was returned from DynamoDB. If no item was returned, it will treat the operation as successful. Otherwise, it will follow the configured strategy.

  • For the UpdateItem operation, the AWS AppSyncDynamoDB resolver does not have enough information to determine if the item currently in DynamoDB matches the expected result, and therefore follows the configured strategy.

If the current state of the object in DynamoDB is different from the expected result, then the AWS AppSyncDynamoDB resolver will follow the configured strategy, to either reject the mutation or invoke a Lambda function to decide what to do next.

Following the "Reject" Strategy

When following the Reject strategy, the AWS AppSyncDynamoDB resolver will return an error for the mutation, and the current value of the object in DynamoDB will also be returned in a data field in the error section of the GraphQL response. The item returned from DynamoDB will be put through the response mapping template to translate it into a format the client expects, and will also be filtered by the selection set.

For example, given the following mutation request:

mutation { updatePerson(id: 1, name: "Steve", expectedVersion: 1) { Name theVersion } }

If the item returned from DynamoDB looks like:

{ "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }

and the response mapping template looks like:

{ "id" : "${context.result.id}", "Name" : "${context.result.name}", "theVersion" : ${context.result.version} }

then the GraphQL response will look like:

{ "data": null, "errors": [ { "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)" "errorType": "DynamoDB:ConditionalCheckFailedException", "data": { "Name": "Steve", "theVersion": 8 }, ... } ] }

Also note that if any fields in the returned object would have been filled by other resolvers if the mutation had succeeded, they will not be resolved when the object is returned in the error section.

Following the "Custom" Strategy

When following the Custom strategy, the AWS AppSyncDynamoDB resolver will invoke a Lambda function to decide what to do next. The Lambda function has three options to choose from:

  • reject the mutation. This will tell the AWS AppSyncDynamoDB resolver to behave as if the configured strategy was Reject, returning an error for the mutation and the current value of the object in DynamoDB as described in the section above.

  • discard the mutation. This will tell the AWS AppSyncDynamoDB resolver to silently ignore the condition check failure, and just return the value in DynamoDB.

  • retry the mutation. This will tell the AWS AppSyncDynamoDB resolver to retry the mutation with a new request mapping document.

The Lambda invocation request

The AWS AppSyncDynamoDB resolver will invoke the Lambda function specified in the lambdaArn. It will use the same service-role-arn configured on the data source. The payload of the invocation has the following structure:

{ "arguments": { ... }, "requestMapping": {... }, "currentValue": { ... }, "resolver": { ... }, "identity": { ... } }

The fields are defined as follows:

arguments

The arguments from the GraphQL mutation. This is the same as the arguments available to the request mapping document in $context.arguments.

requestMapping

The request mapping document for this operation.

currentValue

The current value of the object in DynamoDB.

resolver

Information about the AWS AppSync resolver.

identity

Information about the caller. This is the same as the identity information available to the request mapping document in $context.identity.

A full example of the payload:

{ "arguments": { "id": "1", "name": "Steve", "expectedVersion": 1 }, "requestMapping": { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "attributeValues" : { "name" : { "S" : "Steve" }, "version" : { "N" : 2 } }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : 1 } }, "equalsIgnore": [ "version" ] } }, "currentValue": { "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }, "resolver": { "tableName": "People", "awsRegion": "us-west-2", "parentType": "Mutation", "field": "updatePerson", "outputType": "Person" }, "identity": { "accountId": "123456789012", "sourceIp": "x.x.x.x", "user": "AIDAAAAAAAAAAAAAAAAAA", "userArn": "arn:aws:iam::123456789012:user/appsync" } }

The Lambda Invocation Response

The Lambda function can inspect the invocation payload and apply any business logic to decide how the AWS AppSyncDynamoDB resolver should handle the failure. There are three options for handling the condition check failure:

  • reject the mutation. The response payload for this option must have this structure:

    { "action": "reject" }

    This will tell the AWS AppSyncDynamoDB resolver to behave as if the configured strategy was Reject, returning an error for the mutation and the current value of the object in DynamoDB, as described in the section above.

  • discard the mutation. The response payload for this option must have this structure:

    { "action": "discard" }

    This will tell the AWS AppSyncDynamoDB resolver to silently ignore the condition check failure, and just return the value in DynamoDB.

  • retry the mutation. The response payload for this option must have this structure:

    { "action": "retry", "retryMapping": { ... } }

    This will tell the AWS AppSyncDynamoDB resolver to retry the mutation with a new request mapping document. The structure of the retryMapping section depends on the DynamoDB operation, and is a subset of the full request mapping document for that operation.

    For PutItem, the retryMapping section has the following structure. See PutItem for a description of the attributeValues field.

    { "attributeValues": { ... }, "condition": { "equalsIgnore" = [ ... ], "consistentRead" = true } }

    For UpdateItem, the retryMapping section has the following structure. See UpdateItem for a description of the update section.

    { "update" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value } }, "condition": { "consistentRead" = true } }

    For DeleteItem, the retryMapping section has the following structure.

    { "condition": { "consistentRead" = true } }

    Note that there is no way to specify a different operation or key to work on: the AWS AppSyncDynamoDB resolver will only allow retries of the same operation on the same object. Also note the condition section doesn't allow a conditionalCheckFailedHandler to be specified. If the retry fails, then the AWS AppSyncDynamoDB resolver will follow the Reject strategy.

Here is an example Lambda function to deal with a failed PutItem request. The business logic looks at who made the call: if it was made by jeffTheAdmin then it will retry the request, updating the version and expectedVersion from the item currently in DynamoDB; otherwise it will reject the mutation.

exports.handler = (event, context, callback) => { console.log("Event: "+ JSON.stringify(event)); // Business logic goes here. var response; if ( event.identity.user == "jeffTheAdmin" ) { response = { "action" : "retry", "retryMapping" : { "attributeValues" : event.requestMapping.attributeValues, "condition" : { "expression" : event.requestMapping.condition.expression, "expressionValues" : event.requestMapping.condition.expressionValues } } } response.retryMapping.attributeValues.version = { "N" : event.currentValue.version.N + 1 } response.retryMapping.condition.expressionValues[':expectedVersion'] = event.currentValue.version } else { response = { "action" : "reject" } } console.log("Response: "+ JSON.stringify(response)) callback(null, response) };