Resolver mapping template overview - AWS AppSync

Resolver mapping template overview

AWS AppSync lets you respond to GraphQL requests by performing operations on your resources. For each GraphQL field you wish to run a query or mutation on, a resolver must be attached in order to communicate with a data source. The communication is typically through parameters or operations that are unique to the data source.

Resolvers are the connectors between GraphQl and a data source. They tell AWS AppSync how to translate an incoming GraphQL request into instructions for your backend data source, and how to translate the response from that data source back into a GraphQL response. They are written in Apache Velocity Template Language (VTL), which takes your request as input and outputs a JSON document containing the instructions for the resolver. You can use mapping templates for simple instructions, such as passing in arguments from GraphQL fields, or for more complex instructions, such as looping through arguments to build an item before inserting the item into DynamoDB.

There are two types of resolvers in AppSync which leverage mapping templates in slightly different ways: unit resolvers and pipeline resolvers.

Unit Resolvers

Unit Resolvers are self contained entities which include a request and response template only. Use these for simple, single operations such as listing items from a single data source.

  • Request templates: Take the incoming request after a GraphQL operation is parsed and convert it into a request configuration for the selected data source operation.

  • Response templates: Interpret responses from your data source and map it to the shape of the GraphQL field output type.

Pipeline resolvers

Pipeline resolvers contain one or more functions which are performed in sequential order. Each function includes a request template and response template. A pipeline resolver also has a before template and an after template that surround the sequence of functions that the template contains. The after template maps to the GraphQL field output type. Pipeline resolvers differ from unit resolvers in the way that the response template maps output. A pipeline resolver can map to any output you want, including the input for another function or the after template of the pipeline resolver.

Pipeline resolver functions enable you to write common logic that you can reuse across multiple resolvers in your schema. Functions are attached directly to a data source, and like a unit resolver, contain the same request and response mapping template format.

The following diagram demonstrates the process flow of a unit resolver on the left and a pipeline resolver on the right.


            A diagram of a unit resolver that communicates with a single data source and a
               diagram of a pipeline resolver that communicates with multiple data sources.

Pipeline resolvers contain a superset of the functionality that unit resolvers support, and more, at the cost of a little more complexity.

Example template

For example, suppose you have a DynamoDB data source and a Unit resolver on a field named getPost(id:ID!) that returns a Post type with the following GraphQL query:

getPost(id:1){ id title content }

Your resolver template might look like the following:

{ "version" : "2018–05–29", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) } }

This would substitute the id input parameter value of 1 for ${ctx.args.id} and generate the following JSON:

{ "version" : "2018–05–29", "operation" : "GetItem", "key" : { "id" : { "S" : "1" } } }

AWS AppSync uses this template to generate instructions for communicating with DynamoDB and getting data (or performing other operations as appropriate). After the data returns, AWS AppSync runs it through an optional response mapping template, which you can use to perform data shaping or logic. For example, when we get the results back from DynamoDB, they might look like this:

{ "id" : 1, "theTitle" : "AWS AppSync works offline!", "theContent-part1" : "It also has realtime functionality", "theContent-part2" : "using GraphQL" }

You could choose to join two of the fields into a single field with the following response mapping template:

{ "id" : $util.toJson($context.data.id), "title" : $util.toJson($context.data.theTitle), "content" : $util.toJson("${context.data.theContent-part1} ${context.data.theContent-part2}") }

Here’s how the data is shaped after the template is applied to the data:

{ "id" : 1, "title" : "AWS AppSync works offline!", "content" : "It also has realtime functionality using GraphQL" }

This data is given back as the response to a client as follows:

{ "data": { "getPost": { "id" : 1, "title" : "AWS AppSync works offline!", "content" : "It also has realtime functionality using GraphQL" } } }

Note that under most circumstances, response mapping templates are a simple passthrough of data, differing mostly if you are returning an individual item or a list of items. For an individual item the passthrough is:

$util.toJson($context.result)

For lists the passthrough is usually:

$util.toJson($context.result.items)

To see more examples of both unit and pipeline resolvers, see Resolver tutorials.

Evaluated mapping template deserialization rules

Mapping templates evaluate to a string. In AWS AppSync, the output string must follow a JSON structure to be valid.

Additionally, the following deserialization rules are enforced.

Duplicate keys are not allowed in JSON objects

If the evaluated mapping template string represents a JSON object or contains an object that has duplicate keys, the mapping template returns the following error message:

Duplicate field 'aField' detected on Object. Duplicate JSON keys are not allowed.

Example of a duplicate key in an evaluated request mapping template:

{ "version": "2018–05–29", "operation": "Invoke", "payload": { "field": "getPost", "postId": "1", "field": "getPost" ## key 'field' has been redefined } }

To fix this error, do not redefine keys in JSON objects.

Trailing characters are not allowed in JSON objects

If the evaluated mapping template string represents a JSON object and contains trailing extraneous characters, the mapping template returns the following error message:

Trailing characters at the end of the JSON string are not allowed.

Example of trailing characters in an evaluated request mapping template:

{ "version": "2018–05–29", "operation": "Invoke", "payload": { "field": "getPost", "postId": "1", } }extraneouschars

To fix this error, ensure evaluated templates strictly evaluate to JSON.