AWS AppSync
AWS AppSync Developer Guide

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 execute, such as a Query or Mutation, a Resolver must be attached in order to communicate with a data source. Usually, the communication is through parameters or operations that are unique to the data source.

Mapping templates are a way of indicating to 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 and Pipeline Resolvers.

Unit Resolvers

Unit Resolvers are self contained entities which include request & 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 converts it into a request configuration for the selected data source operation.

  • Response templates: Interprets responses from your data source and maps to the shape of the GraphQL field output type.

Pipeline Resolvers

Pipeline Resolvers contain one or more Functions which are executed in order. Each Function includes a request and response template, and operate in a similar manner, but not exactly the same as Unit Resolvers. What differs is the response template can map to any output you wish, which could be the input for another Function or the After template of the pipeline resolver. The Pipeline Resolver also has a Before and After template which surround the Function execution sequence. The After template maps to the GraphQL field output type. Pipeline resolvers contain a superset of the functionality that Unit Resolvers offer, and more, at the cost of a little more complexity.

Functions allow you to write common logic for reuse across multiple Resolvers in your schema. They are attached directly to a data source and like a Unit resolver, contain the same request and response mapping template format.

A side-by-side diagram of Unit (left) and Pipeline (right) resolvers is below.

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" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : { "S" : "${context.arguments.id}" } } }

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

{ "version" : "2017-02-28", "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" : ${context.data.id}, "title" : "${context.data.theTitle}", "content" : "${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:

$utils.toJson($context.result)

For lists the passthrough is usually:

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

To see more examples of both Unit and Pipeline resolvers please see Resolver Tutorials.