

# Configuring resolvers in AWS AppSync
<a name="resolver-config-overview"></a>

In the previous sections, you learned how to create your GraphQL schema and data source, then linked them together in the AWS AppSync service. In your schema, you may have established one or more fields (operations) in your query and mutation. While the schema described the kinds of data the operations would request from the data source, it never implemented how those operations would behave around the data. 

An operation's behavior is always implemented in the resolver, which will be linked to the field performing the operation. For more information about how resolvers work in general, see the [Resolvers](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html) page.

In AWS AppSync, your resolver is tied to a runtime, which is the environment in which your resolver executes. Runtimes dictate the language that your resolver will be written in. There are currently two supported runtimes: APPSYNC\$1JS (JavaScript) and Apache Velocity Template Language (VTL). 

When implementing resolvers, there is a general structure they follow:
+ **Before step**: When a request is made by the client, the resolvers for the schema fields being used (typically your queries, mutations, subscriptions) are passed the request data. The resolver will begin processing the request data with a before step handler, which allows some preprocessing operations to be performed before the data moves through the resolver.
+ **Function(s)**: After the before step runs, the request is passed to the functions list. The first function in the list will execute against the data source. A function is a subset of your resolver's code containing its own request and response handler. A request handler will take the request data and perform operations against the data source. The response handler will process the data source's response before passing it back to the list. If there is more than one function, the request data will be sent to the next function in the list to be executed. Functions in the list will be executed serially in the order defined by the developer. Once all functions have been executed, the final result is passed to the after step.
+ **After step**: The after step is a handler function that allows you to perform some final operations on the final function's response before passing it to the GraphQL response.

This flow is an example of a pipeline resolver. Pipeline resolvers are supported in both runtimes. However, this is a simplified explanation of what pipeline resolvers can do. Also, we're describing only one possible resolver configuration. For more information about supported resolver configurations, see the [JavaScript resolvers overview](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html) for APPSYNC\$1JS or the [Resolver mapping template overview](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html) for VTL.

As you can see, resolvers are modular. In order for the components of the resolver to work properly, they must be able to peer into the state of the execution from other components. From the [Resolvers](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html) section, you know that each component in the resolver can be passed vital information about the state of the execution as a set of arguments (`args`, `context`, etc.). In AWS AppSync, this is handled strictly by the `context`. It's a container for the information about the field being resolved. This can include everything from arguments being passed, results, authorization data, header data, etc. For more information about the context, see the [Resolver context object reference](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html) for APPSYNC\$1JS or the [Resolver mapping template context reference](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html) for VTL.

The context isn't the only tool you can use to implement your resolver. AWS AppSync supports a wide range of utilities for value generation, error handling, parsing, conversion, etc. You can see a list of utilities [here](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html) for APPSYNC\$1JS or [here](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html) for VTL.

In the following sections, you will learn how to configure resolvers in your GraphQL API.

**Topics**
+ [Creating basic queries (JavaScript)](configuring-resolvers-js.md)
+ [Creating basic queries (VTL)](configuring-resolvers.md)

# Creating basic queries (JavaScript)
<a name="configuring-resolvers-js"></a>

GraphQL resolvers connect the fields in a type’s schema to a data source. Resolvers are the mechanism by which requests are fulfilled.

Resolvers in AWS AppSync use JavaScript to convert a GraphQL expression into a format the data source can use. Alternatively, mapping templates can be written in [Apache Velocity Template Language (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) to convert a GraphQL expression into a format the data source can use.

This section describes how to configure resolvers using JavaScript. The [Resolver tutorials (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html) section provides in-depth tutorials on how to implement resolvers using JavaScript. The [Resolver reference (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html) section provides an explanation of utility operations that can be used with JavaScript resolvers.

We recommend following this guide before attempting to use any of the aforementioned tutorials.

In this section, we will walk through how to create and configure resolvers for queries and mutations.

**Note**  
This guide assumes you have created your schema and have at least one query or mutation. If you're looking for subscriptions (real-time data), then see [this](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html) guide.

In this section, we'll provide some general steps for configuring resolvers along with an example that uses the schema below:

```
// schema.graphql file

input CreatePostInput {
  title: String
  date: AWSDateTime
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
}

type Mutation {
  createPost(input: CreatePostInput!): Post
}

type Query {
  getPost: [Post]
}
```

## Creating basic query resolvers
<a name="create-basic-query-resolver-js"></a>

This section will show you how to make a basic query resolver.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. Enter the details of your schema and data source. See the [Designing your schema](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html) and [Attaching a data source](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) sections for more information.

1. Next to the **Schema** editor, There's a window called **Resolvers**. This box contains a list of the types and fields as defined in your **Schema** window. You can attach resolvers to fields. You will most likely be attaching resolvers to your field operations. In this section, we'll look at simple query configurations. Under the **Query** type, choose **Attach** next to your query's field.

1. On the **Attach resolver** page, under **Resolver type**, you can choose between pipeline or unit resolvers. For more information about these types, see [Resolvers](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html). This guide will make use of `pipeline resolvers`.
**Tip**  
When creating pipeline resolvers, your data source(s) will be attached to the pipeline function(s). Functions are created after you create the pipeline resolver itself, which is why there's no option to set it in this page. If you're using a unit resolver, the data source is tied directly to the resolver, so you would set it in this page.

   For **Resolver runtime**, choose `APPSYNC_JS` to enable the JavaScript runtime.

1. You can enable [caching](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html) for this API. We recommend turning this feature off for now. Choose **Create**.

1. On the **Edit resolver** page, there's a code editor called **Resolver code** that allows you to implement the logic for the resolver handler and response (before and after steps). For more information, see the [JavaScript resolvers overview](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html). 
**Note**  
In our example, we're just going to leave the request blank and the response set to return the last data source result from the [context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html):  

   ```
   import {util} from '@aws-appsync/utils';
   
   export function request(ctx) {
       return {};
   }
   
   export function response(ctx) {
       return ctx.prev.result;
   }
   ```

   Below this section, there's a table called **Functions**. Functions allow you to implement code that can be reused across multiple resolvers. Instead of constantly rewriting or copying code, you can store the source code as a function to be added to a resolver whenever you need it. 

   Functions make up the bulk of a pipeline's operation list. When using multiple functions in a resolver, you set the order of the functions, and they will be run in that order sequentially. They are executed after the request function runs and before the response function begins.

   To add a new function, under **Functions**, choose **Add function**, then **Create new function**. Alternatively, you may see a **Create function** button to choose instead.

   1. Choose a data source. This will be the data source on which the resolver acts.
**Note**  
In our example, we're attaching a resolver for `getPost`, which retrieves a `Post` object by `id`. Let's assume we already set up a DynamoDB table for this schema. Its partition key is set to the `id` and is empty.

   1. Enter a `Function name`.

   1. Under **Function code**, you'll need to implement the function's behavior. This might be confusing, but each function will have its own local request and response handler. The request runs, then the data source invocation is made to handle the request, then the data source response is processed by the response handler. The result is stored in the [context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html) object. Afterward, the next function in the list will run or will be passed to the after step response handler if it's the last one. 
**Note**  
In our example, we're attaching a resolver to `getPost`, which gets a list of `Post` objects from the data source. Our request function will request the data from our table, the table will pass its response to the context (ctx), then the response will return the result in the context. AWS AppSync's strength lies in its interconnectedness with other AWS services. Because we're using DynamoDB, we have a [suite of operations](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html) to simplify things like this. We have some boilerplate examples for other data source types as well.  
Our code will look like this:  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Performs a scan on the dynamodb data source
       */
      export function request(ctx) {
        return { operation: 'Scan' };
      }
      
      /**
       * return a list of scanned post items
       */
      export function response(ctx) {
        return ctx.result.items;
      }
      ```
In this step, we added two functions:  
`request`: The request handler performs the retrieval operation against the data source. The argument contains the context object (`ctx`), or some data that is available to all resolvers performing a particular operation. For example, it might contain authorization data, the field names being resolved, etc. The return statement performs a [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan) operation (see [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html) for examples). Because we're working with DynamoDB, we're allowed to use some of the operations from that service. The scan performs a basic fetch of all items in our table. The result of this operation is stored in the context object as a `result` container before being passed to the response handler. The `request` is run before the response in the pipeline.
`response`: The response handler that returns the output of the `request`. The argument is the updated context object, and the return statement is `ctx.prev.result`. At this point in the guide, you may not be familiar with this value. `ctx` refers to the context object. `prev` refers to the previous operation in the pipeline, which was our `request`. The `result` contains the result(s) of the resolver as it moves through the pipeline. If you put it all together, `ctx.prev.result` is returning the result of the last operation performed, which was the request handler.

   1. Choose **Create** after you're done.

1. Back on the resolver screen, under **Functions**, choose the **Add function** drop-down and add your function to your functions list.

1. Choose **Save** to update the resolver.

------
#### [ CLI ]

**To add your function**
+ Create a function for your pipeline resolver using the `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` command.

  You'll need to enter a few parameters for this particular command:

  1. The `api-id` of your API.

  1. The `name` of the function in the AWS AppSync console.

  1. The `data-source-name`, or the name of the data source the function will use. It must already be created and linked to your GraphQL API in the AWS AppSync service.

  1. The `runtime`, or environment and language of the function. For JavaScript, the name must be `APPSYNC_JS`, and the runtime, `1.0.0`.

  1. The `code`, or request and response handlers of your function. While you can type it in manually, it's far easier to add it to a .txt file (or a similar format) and then pass it in as the argument. 
**Note**  
Our query code will be in a file passed in as the argument:  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Performs a scan on the dynamodb data source
      */
     export function request(ctx) {
       return { operation: 'Scan' };
     }
     
     /**
      * return a list of scanned post items
      */
     export function response(ctx) {
       return ctx.result.items;
     }
     ```

  An example command may look like this:

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name get_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file://~/path/to/file/{filename}.{fileType}
  ```

  An output will be returned in the CLI. Here's an example:

  ```
  {
      "functionConfiguration": {
          "functionId": "ejglgvmcabdn7lx75ref4qeig4",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/ejglgvmcabdn7lx75ref4qeig4",
          "name": "get_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```
**Note**  
Make sure you record the `functionId` somewhere as this will be used to attach the function to the resolver.

**To create your resolver**
+ Create a pipeline function for `Query` by running the `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` command.

  You'll need to enter a few parameters for this particular command:

  1. The `api-id` of your API.

  1. The `type-name`, or the special object type in your schema (Query, Mutation, Subscription).

  1. The `field-name`, or the field operation inside the special object type you want to attach the resolver to.

  1. The `kind`, which specifies a unit or pipeline resolver. Set this to `PIPELINE` to enable pipeline functions.

  1. The `pipeline-config`, or the function(s) to attach to the resolver. Make sure you know the `functionId` values of your functions. Order of listing matters.

  1. The `runtime`, which was `APPSYNC_JS` (JavaScript). The `runtimeVersion` currently is `1.0.0`.

  1. The `code`, which contains the before and after step handlers.
**Note**  
Our query code will be in a file passed in as the argument:  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  An example command may look like this:

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Query \
  --field-name getPost \
  --kind PIPELINE \
  --pipeline-config functions=ejglgvmcabdn7lx75ref4qeig4 \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  An output will be returned in the CLI. Here's an example:

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "getPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/getPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "ejglgvmcabdn7lx75ref4qeig4"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**Tip**  
Before you use the CDK, we recommend reviewing the CDK's [official documentation](https://docs.aws.amazon.com/cdk/v2/guide/home.html) along with AWS AppSync's [CDK reference](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html).  
The steps listed below will only show a general example of the snippet used to add a particular resource. This is **not** meant to be a working solution in your production code. We also assume you already have a working app.

A basic app will need the following things:

1. Service import directives

1. Schema code

1. Data source generator

1. Function code

1. Resolver code

From the [Designing your schema](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html) and [Attaching a data source](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) sections, we know that the stack file will include the import directives of the form:

```
import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
```

**Note**  
In previous sections, we only stated how to import AWS AppSync constructs. In real code, you'll have to import more services just to run the app. In our example, if we were to create a very simple CDK app, we would at least import the AWS AppSync service along with our data source, which was a DynamoDB table. We would also need to import some additional constructs to deploy the app:  

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```
To summarize each of these:  
`import * as cdk from 'aws-cdk-lib';`: This allows you to define your CDK app and constructs such as the stack. It also contains some useful utility functions for our application like manipulating metadata. If you're familiar with this import directive, but are wondering why the cdk core library is not being used here, see the [Migration](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html) page.
`import * as appsync from 'aws-cdk-lib/aws-appsync';`: This imports the [AWS AppSync service](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html).
`import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';`: This imports the [DynamoDB service](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html).
`import { Construct } from 'constructs';`: We need this to define the root [construct](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html).

The type of import depends on the services you're calling. We recommend looking at the CDK documentation for examples. The schema at the top of the page will be a separate file in your CDK app as a `.graphql` file. In the stack file, we can associate it with a new GraphQL using the form:

```
const add_api = new appsync.GraphqlApi(this, 'graphQL-example', {
  name: 'my-first-api',
  schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema.graphql')),
});
```

**Note**  
In the scope `add_api`, we're adding a new GraphQL API using the `new` keyword followed by `appsync.GraphqlApi(scope: Construct, id: string , props: GraphqlApiProps)`. Our scope is `this`, the CFN id is `graphQL-example`, and our props are `my-first-api` (name of the API in the console) and `schema.graphql` (the absolute path to the schema file).

To add a data source, you'll first have to add your data source to the stack. Then, you need to associate it with the GraphQL API using the source-specific method. The association will happen when you make your resolver function. In the meantime, let's use an example by creating the DynamoDB table using `dynamodb.Table`:

```
const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
  partitionKey: {
    name: 'id',
    type: dynamodb.AttributeType.STRING,
  },
});
```

**Note**  
If we were to use this in our example, we'd be adding a new DynamoDB table with the CFN id of `posts-table` and a partition key of `id (S)`.

Next, we need to implement our resolver in the stack file. Here's an example of a simple query that scans for all items in a DynamoDB table:

```
const add_func = new appsync.AppsyncFunction(this, 'func-get-posts', {
  name: 'get_posts_func_1',
  add_api,
  dataSource: add_api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return { operation: 'Scan' };
      }

      export function response(ctx) {
        return ctx.result.items;
      }
  `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
});

new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
  add_api,
  typeName: 'Query',
  fieldName: 'getPost',
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return {};
      }

      export function response(ctx) {
        return ctx.prev.result;
      }
 `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
  pipelineConfig: [add_func],
});
```

**Note**  
First, we created a function called `add_func`. This order of creation may seem a bit counterintuitive, but you have to create the functions in your pipeline resolver before you make the resolver itself. A function follows the form:  

```
AppsyncFunction(scope: Construct, id: string, props: AppsyncFunctionProps)
```
Our scope was `this`, our CFN id was `func-get-posts`, and our props contained the actual function details. Inside props, we included:  
The `name` of the function that will be present in the AWS AppSync console (`get_posts_func_1`).
The GraphQL API we created earlier (`add_api`).
The data source; this is the point where we link the data source to the GraphQL API value, then attach it to the function. We take the table we created (`add_ddb_table`) and attach it to the GraphQL API (`add_api`) using one of the `GraphqlApi` methods ([https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options)). The id value (`table-for-posts`) is the name of the data source in the AWS AppSync console. For a list of source-specific methods, see the following pages:  
[ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
 [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
 [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
 [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
 [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
 [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
 [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 
The code contains our function's request and response handlers, which is a simple scan and return.
The runtime specifies that we want to use the APPSYNC\$1JS runtime version 1.0.0. Note that this is currently the only version available for APPSYNC\$1JS.
Next, we need to attach the function to the pipeline resolver. We created our resolver using the form:  

```
Resolver(scope: Construct, id: string, props: ResolverProps)
```
Our scope was `this`, our CFN id was `pipeline-resolver-get-posts`, and our props contained the actual function details. Inside the props, we included:  
The GraphQL API we created earlier (`add_api`).
The special object type name; this is a query operation, so we simply added the value `Query`.
The field name (`getPost`) is the name of the field in the schema under the `Query` type.
The code contains your before and after handlers. Our example just returns whatever results were in the context after the function performed its operation.
The runtime specifies that we want to use the APPSYNC\$1JS runtime version 1.0.0. Note that this is currently the only version available for APPSYNC\$1JS.
The pipeline config contains the reference to the function we created (`add_func`).

------

To summarize what happened in this example, you saw an AWS AppSync function that implemented a request and response handler. The function was responsible for interacting with your data source. The request handler sent a `Scan` operation to AWS AppSync, instructing it on what operation to perform against your DynamoDB data source. The response handler returned the list of items (`ctx.result.items`). The list of items was then mapped to the `Post` GraphQL type automatically. 

## Creating basic mutation resolvers
<a name="creating-basic-mutation-resolvers-js"></a>

This section will show you how to make a basic mutation resolver.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. Under the **Resolvers** section and the **Mutation** type, choose **Attach** next to your field.
**Note**  
In our example, we're attaching a resolver for `createPost`, which adds a `Post` object to our table. Let's assume we're using the same DynamoDB table from the last section. Its partition key is set to the `id` and is empty.

1. On the **Attach resolver** page, under **Resolver type**, choose `pipeline resolvers`. As a reminder, you can find more information about resolvers [here](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html). For **Resolver runtime**, choose `APPSYNC_JS` to enable the JavaScript runtime.

1. You can enable [caching](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html) for this API. We recommend turning this feature off for now. Choose **Create**.

1. Choose **Add function**, then choose **Create new function**. Alternatively, you may see a **Create function** button to choose instead.

   1. Choose your data source. This should be the source whose data you will manipulate with the mutation.

   1. Enter a `Function name`.

   1. Under **Function code**, you'll need to implement the function's behavior. This is a mutation, so the request will ideally perform some state-changing operation on the invoked data source. The result will be processed by the response function.
**Note**  
`createPost` is adding, or "putting", a new `Post` in the table with our parameters as the data. We could add something like this:   

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Sends a request to `put` an item in the DynamoDB data source
       */
      export function request(ctx) {
        return {
          operation: 'PutItem',
          key: util.dynamodb.toMapValues({id: util.autoId()}),
          attributeValues: util.dynamodb.toMapValues(ctx.args.input),
        };
      }
      
      /**
       * returns the result of the `put` operation
       */
      export function response(ctx) {
        return ctx.result;
      }
      ```
In this step, we also added `request` and `response` functions:  
`request`: The request handler accepts the context as the argument. The request handler return statement performs a [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem) command, which is a built-in DynamoDB operation (see [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html) or [here](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData) for examples). The `PutItem` command adds a `Post` object to our DynamoDB table by taking the partition `key` value (automatically generated by `util.autoid()`) and `attributes` from the context argument input (these are the values we will pass in our request). The `key` is the `id` and `attributes` are the `date` and `title` field arguments. They're both preformatted through the [https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js](https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js) helper to work with the DynamoDB table.
`response`: The response accepts the updated context and returns the result of the request handler.

   1. Choose **Create** after you're done.

1. Back on the resolver screen, under **Functions**, choose the **Add function** drop-down and add your function to your functions list.

1. Choose **Save** to update the resolver.

------
#### [ CLI ]

**To add your function**
+ Create a function for your pipeline resolver using the `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)` command.

  You'll need to enter a few parameters for this particular command:

  1. The `api-id` of your API.

  1. The `name` of the function in the AWS AppSync console.

  1. The `data-source-name`, or the name of the data source the function will use. It must already be created and linked to your GraphQL API in the AWS AppSync service.

  1. The `runtime`, or environment and language of the function. For JavaScript, the name must be `APPSYNC_JS`, and the runtime, `1.0.0`.

  1. The `code`, or request and response handlers of your function. While you can type it in manually, it's far easier to add it to a .txt file (or a similar format) then pass it in as the argument. 
**Note**  
Our query code will be in a file passed in as the argument:  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({id: util.autoId()}),
         attributeValues: util.dynamodb.toMapValues(ctx.args.input),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  An example command may look like this:

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name add_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  An output will be returned in the CLI. Here's an example:

  ```
  {
      "functionConfiguration": {
          "functionId": "vulcmbfcxffiram63psb4dduoa",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/vulcmbfcxffiram63psb4dduoa",
          "name": "add_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output foes here"
      }
  }
  ```
**Note**  
Make sure you record the `functionId` somewhere as this will be used to attach the function to the resolver.

**To create your resolver**
+ Create a pipeline function for `Mutation` by running the `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)` command.

  You'll need to enter a few parameters for this particular command:

  1. The `api-id` of your API.

  1. The `type-name`, or the special object type in your schema (Query, Mutation, Subscription).

  1. The `field-name`, or the field operation inside the special object type you want to attach the resolver to.

  1. The `kind`, which specifies a unit or pipeline resolver. Set this to `PIPELINE` to enable pipeline functions.

  1. The `pipeline-config`, or the function(s) to attach to the resolver. Make sure you know the `functionId` values of your functions. Order of listing matters.

  1. The `runtime`, which was `APPSYNC_JS` (JavaScript). The `runtimeVersion` currently is `1.0.0`.

  1. The `code`, which contains the before and after step.
**Note**  
Our query code will be in a file passed in as the argument:  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  An example command may look like this:

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Mutation \
  --field-name createPost \
  --kind PIPELINE \
  --pipeline-config functions=vulcmbfcxffiram63psb4dduoa \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  An output will be returned in the CLI. Here's an example:

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "createPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/createPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "vulcmbfcxffiram63psb4dduoa"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**Tip**  
Before you use the CDK, we recommend reviewing the CDK's [official documentation](https://docs.aws.amazon.com/cdk/v2/guide/home.html) along with AWS AppSync's [CDK reference](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html).  
The steps listed below will only show a general example of the snippet used to add a particular resource. This is **not** meant to be a working solution in your production code. We also assume you already have a working app.
+ To make a mutation, assuming you're in the same project, you can add it to the stack file like the query. Here's a modified function and resolver for a mutation that adds a new `Post` to the table:

  ```
  const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
    name: 'add_posts_func_1',
    add_api,
    dataSource: add_api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {
                operation: 'PutItem',
                key: util.dynamodb.toMapValues({id: util.autoId()}),
                attributeValues: util.dynamodb.toMapValues(ctx.args.input),
              };
            }
  
            export function response(ctx) {
              return ctx.result;
            }
        `), 
    runtime: appsync.FunctionRuntime.JS_1_0_0,
  });
  
  new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
    add_api,
    typeName: 'Mutation',
    fieldName: 'createPost',
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {};
            }
  
            export function response(ctx) {
              return ctx.prev.result;
            }
        `),
    runtime: appsync.FunctionRuntime.JS_1_0_0,
    pipelineConfig: [add_func_2],
  });
  ```
**Note**  
Since this mutation and the query are similarly structured, we'll just explain the changes we made to make the mutation.   
In the function, we changed the CFN id to `func-add-post` and name to `add_posts_func_1` to reflect the fact that we're adding `Posts` to the table. In the data source, we made a new association to our table (`add_ddb_table`) in the AWS AppSync console as `table-for-posts-2` because the `addDynamoDbDataSource` method requires it. Keep in mind, this new association is still using the same table we created earlier, but we now have two connections to it in the AWS AppSync console: one for the query as `table-for-posts` and one for the mutation as `table-for-posts-2`. The code was changed to add a `Post` by generating its `id` value automatically and accepting a client's input for the rest of the fields.  
In the resolver, we changed the id value to `pipeline-resolver-create-posts` to reflect the fact that we're adding `Posts` to the table. To reflect the mutation in the schema, the type name was changed to `Mutation`, and the name, `createPost`. The pipeline config was set to our new mutation function `add_func_2`.

------

To summarize what's happening in this example, AWS AppSync automatically converts arguments defined in the `createPost` field from your GraphQL schema into DynamoDB operations. The example stores records in DynamoDB using a key of `id`, which is automatically created using our `util.autoId()` helper. All of the other fields you pass to the context arguments (`ctx.args.input`) from requests made in the AWS AppSync console or otherwise will be stored as the table's attributes. Both the key and the attributes are automatically mapped to a compatible DynamoDB format using the `util.dynamodb.toMapValues(values)` helper.

AWS AppSync also supports test and debug workflows for editing resolvers. You can use a mock `context` object to see the transformed value of the template before invoking it. Optionally, you can view the full request to a data source interactively when you run a query. For more information, see [Test and debug resolvers (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/test-debug-resolvers-js.html) and [Monitoring and logging](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html#aws-appsync-monitoring).

## Advanced resolvers
<a name="advanced-resolvers-js"></a>

If you are following the optional pagination section in [Designing your schema](designing-your-schema.md#aws-appsync-designing-your-schema), you still need to add your resolver to your request to make use of pagination. Our example used a query pagination called `getPosts` to return only a portion of the things requested at a time. Our resolver's code on that field may look like this:

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  const { limit = 20, nextToken } = ctx.args;
  return { operation: 'Scan', limit, nextToken };
}

/**
 * @returns the result of the `put` operation
 */
export function response(ctx) {
  const { items: posts = [], nextToken } = ctx.result;
  return { posts, nextToken };
}
```

In the request, we pass in the context of the request. Our `limit` is *20*, meaning we return up to 20 `Posts` in the first query. Our `nextToken` cursor is fixed to the first `Post` entry in the data source. These are passed to the args. The request then performs a scan from the first `Post` up to the scan limit number. The data source stores the result in the context, which is passed to the response. The response returns the `Posts` it retrieved, then sets the `nextToken` is set to the `Post` entry right after the limit. The next request is sent out to do the exact same thing but starting at the offset right after the first query. Keep in mind that these sorts of requests are done sequentially and not in parallel.

# Testing and debugging resolvers in AWS AppSync (JavaScript)
<a name="test-debug-resolvers-js"></a>

AWS AppSync executes resolvers on a GraphQL field against a data source. When working with pipeline resolvers, functions interact with your data sources. As described in the [JavaScript resolvers overview](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html), functions communicate with data sources by using request and response handlers written in JavaScript and running on the `APPSYNC_JS` runtime. This enables you to provide custom logic and conditions before and after communicating with the data source.

To help developers write, test, and debug these resolvers, the AWS AppSync console also provides tools to create a GraphQL request and response with mock data down to the individual field resolver. Additionally, you can perform queries, mutations, and subscriptions in the AWS AppSync console and see a detailed log stream of the entire request from Amazon CloudWatch. This includes results from the data source.

## Testing with mock data
<a name="testing-with-mock-data-js"></a>

When a GraphQL resolver is invoked, it contains a `context` object that has relevant information about the request. This includes arguments from a client, identity information, and data from the parent GraphQL field. It also stores the results from the data source, which can be used in the response handler. For more information about this structure and the available helper utilities to use when programming, see the [Resolver context object reference](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html).

When writing or editing a resolver function, you can pass a *mock* or *test context* object into the console editor. This enables you to see how both the request and the response handlers evaluate without actually running against a data source. For example, you can pass a test `firstname: Shaggy` argument and see how it evaluates when using `ctx.args.firstname` in your template code. You could also test the evaluation of any utility helpers such as `util.autoId()` or `util.time.nowISO8601()`.

### Testing resolvers
<a name="test-a-resolver-js"></a>

This example will use the AWS AppSync console to test resolvers.

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Functions**.

1. Choose an existing function.

1. At the top of the **Update function** page, choose **Select test context**, then choose **Create new context**.

1. Select a sample context object or populate the JSON manually in the **Configure test context** window below.

1. Enter a **Text context name**.

1. Choose the **Save** button.

1. To evaluate your resolver using this mocked context object, choose **Run Test**.

For a more practical example, suppose you have an app storing a GraphQL type of `Dog` that uses automatic ID generation for objects and stores them in Amazon DynamoDB. You also want to write some values from the arguments of a GraphQL mutation and allow only specific users to see a response. The following snippet shows what the schema might look like:

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

You can write an AWS AppSync function and add it to your `addDog` resolver to handle the mutation. To test your AWS AppSync function, you can populate a context object like the following example. The following has arguments from the client of `name` and `age`, and a `username` populated in the `identity` object:

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

You can test your AWS AppSync function using the following code:

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

export function request(ctx) {
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id: util.autoId() }),
    attributeValues: util.dynamodb.toMapValues(ctx.args),
  };
}

export function response(ctx) {
  if (ctx.identity.username === 'Nadia') {
    console.log("This request is allowed")
    return ctx.result;
  }
  util.unauthorized();
}
```

The evaluated request and response handler has the data from your test context object and the generated value from `util.autoId()`. Additionally, if you were to change the `username` to a value other than `Nadia`, the results won’t be returned because the authorization check would fail. For more information about fine-grained access control, see [Authorization use cases](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases).

### Testing request and response handlers with AWS AppSync's APIs
<a name="testing-with-appsync-api-js"></a>

You can use the `EvaluateCode` API command to remotely test your code with mocked data. To get started with the command, make sure you have added the `appsync:evaluateMappingCode` permission to your policy. For example:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateCode",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

You can leverage the command by using the [AWS CLI](https://aws.amazon.com/cli/) or [AWS SDKs](https://aws.amazon.com/tools/). For example, take the `Dog` schema and its AWS AppSync function request and response handlers from the previous section. Using the CLI on your local station, save the code to a file named `code.js`, then save the `context` object to a file named `context.json`. From your shell, run the following command:

```
$ aws appsync evaluate-code \
  --code file://code.js \
  --function response \
  --context file://context.json \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0
```

The response contains an `evaluationResult` containing the payload returned by your handler. It also contains a `logs` object, that holds the list of logs that were generated by your handler during the evaluation. This makes it easy to debug your code execution and see information about your evaluation to help troubleshoot. For example:

```
{
    "evaluationResult": "{\"breed\":\"Miniature Schnauzer\",\"color\":\"black_grey\"}",
    "logs": [
        "INFO - code.js:13:5: \"This request is allowed\""
    ]
}
```

The `evaluationResult` can be parsed as JSON, which gives: 

```
{
  "breed": "Miniature Schnauzer",
  "color": "black_grey"
}
```

Using the SDK, you can easily incorporate tests from your favorite test suite to validate your handlers' behavior. We recommend creating tests using the [Jest Testing Framework](https://jestjs.io/), but any testing suite works. The following snippet shows a hypothetical validation run. Note that we expect the evaluation response to be valid JSON, so we use `JSON.parse` to retrieve JSON from the string response:

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })
const runtime = {name:'APPSYNC_JS',runtimeVersion:'1.0.0')

test('request correctly calls DynamoDB', async () => {
  const code = fs.readFileSync('./code.js', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateCode({ code, context, runtime, function: 'request' }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 This yields the following result:

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 totalTime: 1.511 s, estimated 2 s
```

## Debugging a live query
<a name="debugging-a-live-query-js"></a>

There’s no substitute for an end-to-end test and logging to debug a production application. AWS AppSync lets you log errors and full request details using Amazon CloudWatch. Additionally, you can use the AWS AppSync console to test GraphQL queries, mutations, and subscriptions and live stream log data for each request back into the query editor to debug in real time. For subscriptions, the logs display connection-time information.

To perform this, you need to have Amazon CloudWatch logs enabled in advance, as described in [Monitoring and logging](monitoring.md#aws-appsync-monitoring). Next, in the AWS AppSync console, choose the **Queries** tab and then enter a valid GraphQL query. In the lower-right section, click and drag the **Logs** window to open the logs view. At the top of the page, choose the play arrow icon to run your GraphQL query. In a few moments, your full request and response logs for the operation are streamed to this section and you can view them in the console.

# Configuring and using pipeline resolvers in AWS AppSync (JavaScript)
<a name="pipeline-resolvers-js"></a>

AWS AppSync executes resolvers on a GraphQL field. In some cases, applications require executing multiple operations to resolve a single GraphQL field. With pipeline resolvers, developers can now compose operations called Functions and execute them in sequence. Pipeline resolvers are useful for applications that, for instance, require performing an authorization check before fetching data for a field.

For more information about the architecture of a JavaScript pipeline resolver, see the [JavaScript resolvers overview](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html#anatomy-of-a-pipeline-resolver-js).

## Step 1: Creating a pipeline resolver
<a name="create-a-pipeline-resolver-js"></a>

In the AWS AppSync console, go to the **Schema** page.

Save the following schema:

```
schema {
    query: Query
    mutation: Mutation
}

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

We are going to wire a pipeline resolver to the **signUp** field on the **Mutation** type. In the **Mutation** type on the right side, choose **Attach** next to the `signUp` mutation field. Set the resolver to `pipeline resolver` and the `APPSYNC_JS` runtime, then create the resolver.

Our pipeline resolver signs up a user by first validating the email address input and then saving the user in the system. We are going to encapsulate the email validation inside a **validateEmail** function and the saving of the user inside a **saveUser** function. The **validateEmail** function executes first, and if the email is valid, then the **saveUser** function executes.

The execution flow will be as follows:

1. Mutation.signUp resolver request handler

1. validateEmail function

1. saveUser function

1. Mutation.signUp resolver response handler

Because we will probably reuse the **validateEmail** function in other resolvers on our API, we want to avoid accessing `ctx.args` because these will change from one GraphQL field to another. Instead, we can use the `ctx.stash` to store the email attribute from the `signUp(input: Signup)` input field argument.

Update your resolver code by replacing your request and response functions:

```
export function request(ctx) {
    ctx.stash.email = ctx.args.input.email
    return {};
}

export function response(ctx) {
    return ctx.prev.result;
}
```

Choose **Create** or **Save** to update the resolver.

## Step 2: Creating a function
<a name="create-a-function-js"></a>

From the pipeline resolver page, in the **Functions** section, click on **Add function**, then **Create new function**. It is also possible to create functions without going through the resolver page; to do this, in the AWS AppSync console, go to the **Functions** page. Choose the **Create function** button. Let’s create a function that checks if an email is valid and comes from a specific domain. If the email is not valid, the function raises an error. Otherwise, it forwards whatever input it was given.

Make sure you have created a data source of the **NONE** type. Choose this data source in the **Data source name** list. For the **function name**, enter in `validateEmail`. In the **function code** area, overwrite everything with this snippet:

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

export function request(ctx) {
  const { email } = ctx.stash;
  const valid = util.matches(
    '^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com',
    email
  );
  if (!valid) {
    util.error(`"${email}" is not a valid email.`);
  }

  return { payload: { email } };
}

export function response(ctx) {
  return ctx.result;
}
```

Review your inputs, then choose **Create**. We just created our **validateEmail** function. Repeat these steps to create the **saveUser** function with the following code (For the sake of simplicity, we use a **NONE** data source and pretend the user has been saved in the system after the function executes.):

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

export function request(ctx) {
  return ctx.prev.result;
}

export function response(ctx) {
  ctx.result.id = util.autoId();
  return ctx.result;
}
```

We just created our **saveUser** function.

## Step 3: Adding a function to a pipeline resolver
<a name="adding-a-function-to-a-pipeline-resolver-js"></a>

Our functions should have been added automatically to the pipeline resolver we just created. If this wasn't the case, or you created the functions through the **Functions** page, you can click on **Add function** back on the `signUp` resolver page to attach them. Add both the **validateEmail** and **saveUser** functions to the resolver. The **validateEmail** function should be placed before the **saveUser** function. As you add more functions, you can use the **move up** and **move down** options to reorganize the order of execution of your functions. Review your changes, then choose **Save**.

## Step 4: Running a query
<a name="running-a-query-js"></a>

In the AWS AppSync console, go to the **Queries** page. In the explorer, ensure that you're using your mutation. If you aren't, choose `Mutation` in the drop-down list, then choose `+`. Enter the following query:

```
mutation {
  signUp(input: {email: "nadia@myvaliddomain.com", username: "nadia"}) {
    id
    username
  }
}
```

This should return something like:

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "username": "nadia"
    }
  }
}
```

We have successfully signed up our user and validated the input email using a pipeline resolver.

# Creating basic queries (VTL)
<a name="configuring-resolvers"></a>

**Note**  
We now primarily support the APPSYNC\$1JS runtime and its documentation. Please consider using the APPSYNC\$1JS runtime and its guides [here](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html).

GraphQL resolvers connect the fields in a type’s schema to a data source. Resolvers are the mechanism by which requests are fulfilled. AWS AppSync can automatically create and connect resolvers from a schema or create a schema and connect resolvers from an existing table without you needing to write any code.

Resolvers in AWS AppSync use JavaScript to convert a GraphQL expression into a format the data source can use. Alternatively, mapping templates can be written in [Apache Velocity Template Language (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) to convert a GraphQL expression into a format the data source can use.

This section will show you how to configure resolvers using VTL. An introductory tutorial-style programming guide for writing resolvers can be found in [Resolver mapping template programming guide](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide), and helper utilities available to use when programming can be found in [Resolver mapping template context reference](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference). AWS AppSync also has built-in test and debug flows that you can use when you’re editing or authoring from scratch. For more information, see [Test and debug resolvers](test-debug-resolvers.md#aws-appsync-test-debug-resolvers).

We recommend following this guide before attempting to to use any of the aforementioned tutorials.

In this section, we will walk through how to create a resolver, add a resolver for mutations, and use advanced configurations.

## Create your first resolver
<a name="create-your-first-resolver"></a>

Following the examples from the previous sections, the first step is to create a resolver for your `Query` type.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. On the right-hand side of the page, there's a window called **Resolvers**. This box contains a list of the types and fields as defined in your **Schema** window on the left-hand side of the page. You're able to attach resolvers to fields. For example, under the **Query** type, choose **Attach** next to the `getTodos` field.

1. On the **Create Resolver** page, choose the data source you created in the [Attaching a data source](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) guide. In the **Configure mapping templates** window, you can choose both the generic request and response mapping templates using the drop-down list to the right or write your own.
**Note**  
The pairing of a request mapping template to a response mapping template is called a unit resolver. Unit resolvers are typically meant to perform rote operations; we recommend using them only for singular operations with a small number of data sources. For more complex operations, we recommend using pipeline resolvers, which can execute multiple operations with multiple data sources sequentially.  
For more information about the difference between request and response mapping templates, see [Unit resolvers](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-mapping-template-reference-overview.html#unit-resolvers).  
For more information about using pipeline resolvers, see [Pipeline resolvers](pipeline-resolvers.md#aws-appsync-pipeline-resolvers).

1. For common use cases, the AWS AppSync console has built-in templates that you can use for getting items from data sources (e.g., all item queries, individual lookups, etc.). For example, on the simple version of the schema from [Designing your schema](designing-your-schema.md#aws-appsync-designing-your-schema) where `getTodos` didn’t have pagination, the request mapping template for listing items is as follows:

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

1. You always need a response mapping template to accompany the request. The console provides a default with the following passthrough value for lists:

   ```
   $util.toJson($ctx.result.items)
   ```

   In this example, the `context` object (aliased as `$ctx`) for lists of items has the form `$context.result.items`. If your GraphQL operation returns a single item, it would be `$context.result`. AWS AppSync provides helper functions for common operations, such as the `$util.toJson` function listed previously, to format responses properly. For a full list of functions, see [Resolver mapping template utility reference](resolver-util-reference.md#aws-appsync-resolver-mapping-template-util-reference).

1. Choose **Save Resolver**.

------
#### [ API ]

1. Create a resolver object by calling the [https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html) API.

1. You can modify your resolver's fields by calling the [https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html) API.

------
#### [ CLI ]

1. Create a resolver by running the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) command.

   You'll need to type in 6 parameters for this particular command:

   1. The `api-id` of your API.

   1. The `type-name` of the type that you want to modify in your schema. In the console example, this was `Query`.

   1. The `field-name` of the field that you want to modify in your type. In the console example, this was `getTodos`.

   1. The `data-source-name` of the data source you created in the [Attaching a data source](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) guide.

   1. The `request-mapping-template`, which is the body of the request. In the console example, this was:

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

   1. The `response-mapping-template`, which is the body of the response. In the console example, this was:

      ```
      $util.toJson($ctx.result.items)
      ```

   An example command may look like this:

   ```
   aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Query --field-name getTodos --data-source-name TodoTable --request-mapping-template "{ "version" : "2017-02-28", "operation" : "Scan", }" --response-mapping-template ""$"util.toJson("$"ctx.result.items)"
   ```

   An output will be returned in the CLI. Here's an example:

   ```
   {
       "resolver": {
           "kind": "UNIT",
           "dataSourceName": "TodoTable",
           "requestMappingTemplate": "{ version : 2017-02-28, operation : Scan, }",
           "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query/resolvers/getTodos",
           "typeName": "Query",
           "fieldName": "getTodos",
           "responseMappingTemplate": "$util.toJson($ctx.result.items)"
       }
   }
   ```

1. To modify a resolver's fields and/or mapping templates, run the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html) command.

   With the exception of the `api-id` parameter, the parameters used in the `create-resolver` command will be overwritten by the new values from the `update-resolver` command.

------

## Adding a resolver for mutations
<a name="adding-a-resolver-for-mutations"></a>

The next step is to create a resolver for your `Mutation` type.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. Under the **Mutation** type, choose **Attach** next to the `addTodo` field.

1. On the **Create Resolver** page, choose the data source you created in the [Attaching a data source](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html) guide.

1. In the **Configure mapping templates** window, you'll need to modify the request template because this is a mutation where you’re adding a new item to DynamoDB. Use the following request mapping template:

   ```
   {
       "version" : "2017-02-28",
       "operation" : "PutItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

1. AWS AppSync automatically converts arguments defined in the `addTodo` field from your GraphQL schema into DynamoDB operations. The previous example stores records in DynamoDB using a key of `id`, which is passed through from the mutation argument as `$ctx.args.id`. All of the other fields you pass through are automatically mapped to DynamoDB attributes with `$util.dynamodb.toMapValuesJson($ctx.args)`.

   For this resolver, use the following response mapping template:

   ```
   $util.toJson($ctx.result)
   ```

   AWS AppSync also supports test and debug workflows for editing resolvers. You can use a mock `context` object to see the transformed value of the template before invoking. Optionally, you can view the full request execution to a data source interactively when you run a query. For more information, see [Test and debug resolvers](test-debug-resolvers.md#aws-appsync-test-debug-resolvers) and [Monitoring and logging](monitoring.md#aws-appsync-monitoring).

1. Choose **Save Resolver**.

------
#### [ API ]

You can also do this with APIs by utilizing the commands in the [Create your first resolver](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) section and the parameter details from this section.

------
#### [ CLI ]

You can also do this in the CLI by utilizing the commands in the [Create your first resolver](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) section and the parameter details from this section.

------

At this point, if you’re not using the advanced resolvers you can begin using your GraphQL API as outlined in [Using your API](using-your-api.md#aws-appsync-using-your-api).

## Advanced resolvers
<a name="advanced-resolvers"></a>

If you are following the Advanced section and you’re building a sample schema in [Designing your schema](designing-your-schema.md#aws-appsync-designing-your-schema) to do a paginated scan, use the following request template for the `getTodos` field instead:

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": $util.defaultIfNull(${ctx.args.limit}, 20),
    "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))
}
```

For this pagination use case, the response mapping is more than just a passthrough because it must contain both the *cursor* (so that the client knows what page to start at next) and the result set. The mapping template is as follows:

```
{
    "todos": $util.toJson($context.result.items),
    "nextToken": $util.toJson($context.result.nextToken)
}
```

The fields in the preceding response mapping template should match the fields defined in your `TodoConnection` type.

For the case of relations where you have a `Comments` table and you’re resolving the comments field on the `Todo` type (which returns a type of `[Comment]`), you can use a mapping template that runs a query against the second table. To do this, you must have already created a data source for the `Comments` table as outlined in [Attaching a data source](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch).

**Note**  
We’re using a query operation against a second table for illustrative purposes only. You could use another operation against DynamoDB instead. In addition, you could pull the data from another data source, such as AWS Lambda or Amazon OpenSearch Service, because the relation is controlled by your GraphQL schema.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. Under the **Todo** type, choose **Attach** next to the `comments` field.

1. On the **Create Resolver** page, choose your **Comments** table data source. The default name for the **Comments** table from the quickstart guides is `AppSyncCommentTable`, but it may vary depending on what name you gave it.

1. Add the following snippet to your request mapping template:

   ```
   {
       "version": "2017-02-28",
       "operation": "Query",
       "index": "todoid-index",
       "query": {
           "expression": "todoid = :todoid",
           "expressionValues": {
               ":todoid": {
                   "S": $util.toJson($context.source.id)
               }
           }
       }
   }
   ```

1. The `context.source` references the parent object of the current field that’s being resolved. In this example, `source.id` refers to the individual `Todo` object, which is then used for the query expression.

   You can use the passthrough response mapping template as follows:

   ```
   $util.toJson($ctx.result.items)
   ```

1. Choose **Save Resolver**.

1. Finally, back on the **Schema** page in the console, attach a resolver to the `addComment` field, and specify the data source for the `Comments` table. The request mapping template in this case is a simple `PutItem` with the specific `todoid` that is commented on as an argument, but you use the `$utils.autoId()` utility to create a unique sort key for the comment as follows:

   ```
   {
       "version": "2017-02-28",
       "operation": "PutItem",
       "key": {
           "todoid": { "S": $util.toJson($context.arguments.todoid) },
           "commentid": { "S": "$util.autoId()" }
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

   Use a passthrough response template as follows:

   ```
   $util.toJson($ctx.result)
   ```

------
#### [ API ]

You can also do this with APIs by utilizing the commands in the [Create your first resolver](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) section and the parameter details from this section.

------
#### [ CLI ]

You can also do this in the CLI by utilizing the commands in the [Create your first resolver](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver) section and the parameter details from this section.

------

# Disabling VTL mapping templates with direct Lambda resolvers (VTL)
<a name="direct-lambda-reference"></a>

**Note**  
We now primarily support the APPSYNC\$1JS runtime and its documentation. Please consider using the APPSYNC\$1JS runtime and its guides [here](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html).

With direct Lambda resolvers, you can circumvent the use of VTL mapping templates when using AWS Lambda data sources. AWS AppSync can provide a default payload to your Lambda function as well as a default translation from a Lambda function's response to a GraphQL type. You can choose to provide a request template, a response template, or neither and AWS AppSync will handle it accordingly. 

To learn more about the default request payload and response translation that AWS AppSync provides, see the [Direct Lambda resolver reference](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers). For more information on setting up an AWS Lambda data source and setting up an IAM Trust Policy, see [Attaching a data source](attaching-a-data-source.md). 

## Configure direct Lambda resolvers
<a name="direct-lambda-reference-resolvers"></a>

The following sections will show you how to attach Lambda data sources and add Lambda resolvers to your fields.

### Add a Lambda data source
<a name="direct-lambda-datasource"></a>

Before you can activate direct Lambda resolvers, you must add a Lambda data source.

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Data sources**.

1. Choose **Create data source**.

   1. For **Data source name**, enter a name for your data source, such as **myFunction**. 

   1. For **Data source type**, choose **AWS Lambda function**.

   1. For **Region**, choose the appropriate region.

   1. For **Function ARN**, choose the Lambda function from the dropdown list. You can search for the function name or manually enter the ARN of the function you want to use. 

   1. Create a new IAM role (recommended) or choose an existing role that has the `lambda:invokeFunction` IAM permission. Existing roles need a trust policy, as explained in the [Attaching a data source](attaching-a-data-source.md) section. 

      The following is an example IAM policy that has the required permissions to perform operations on the resource:

------
#### [ JSON ]

****  

      ```
      { 
           "Version":"2012-10-17",		 	 	  
           "Statement": [ 
               { 
                   "Effect": "Allow", 
                   "Action": [ "lambda:invokeFunction" ], 
                   "Resource": [ 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction", 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" 
                   ] 
               } 
           ] 
       }
      ```

------

1. Choose the **Create** button.

------
#### [ CLI ]

1. Create a data source object by running the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html) command.

   You'll need to type in 4 parameters for this particular command:

   1. The `api-id` of your API.

   1. The `name` of your data source. In the console example, this is the **Data source name**.

   1. The `type` of data source. In the console example, this is **AWS Lambda function**.

   1. The `lambda-config`, which is the **Function ARN** in the console example.
**Note**  
There are other parameters such as `Region` that must be configured but will usually default to your CLI configuration values.

   An example command may look like this:

   ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name myFunction --type AWS_LAMBDA --lambda-config lambdaFunctionArn=arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example
   ```

   An output will be returned in the CLI. Here's an example:

   ```
   {
       "dataSource": {
           "dataSourceArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/datasources/myFunction",
           "type": "AWS_LAMBDA",
           "name": "myFunction",
           "lambdaConfig": {
               "lambdaFunctionArn": "arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example"
           }
       }
   }
   ```

1. To modify a data source's attributes, run the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html) command.

   With the exception of the `api-id` parameter, the parameters used in the `create-data-source` command will be overwritten by the new values from the `update-data-source` command.

------

### Activate direct Lambda resolvers
<a name="direct-lambda-enable-templates"></a>

After creating a Lambda data source and setting up the appropriate IAM role to allow AWS AppSync to invoke the function, you can link it to a resolver or pipeline function. 

------
#### [ Console ]

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. In the **Resolvers** window, choose a field or operation and then select the **Attach** button.

1. In the **Create new resolver** page, choose the Lambda function from the dropdown list.

1. In order to leverage direct Lambda resolvers, confirm that request and response mapping templates are disabled in the **Configure mapping templates** section.

1. Choose the **Save Resolver** button.

------
#### [ CLI ]
+ Create a resolver by running the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html) command.

  You'll need to type in 6 parameters for this particular command:

  1. The `api-id` of your API.

  1. The `type-name` of the type in your schema.

  1. The `field-name` of the field in your schema.

  1. The `data-source-name`, or your Lambda function's name.

  1. The `request-mapping-template`, which is the body of the request. In the console example, this was disabled:

     ```
     " "
     ```

  1. The `response-mapping-template`, which is the body of the response. In the console example, this was also disabled:

     ```
     " "
     ```

  An example command may look like this:

  ```
  aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Subscription --field-name onCreateTodo --data-source-name LambdaTest --request-mapping-template " " --response-mapping-template " "
  ```

  An output will be returned in the CLI. Here's an example:

  ```
  {
      "resolver": {
          "resolverArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/types/Subscription/resolvers/onCreateTodo",
          "typeName": "Subscription",
          "kind": "UNIT",
          "fieldName": "onCreateTodo",
          "dataSourceName": "LambdaTest"
      }
  }
  ```

------

When you disable your mapping templates, there are several additional behaviors that will occur in AWS AppSync:
+ By disabling a mapping template, you are signalling to AWS AppSync that you accept the default data translations specified in the [Direct Lambda resolver reference](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers).
+ By disabling the request mapping template, your Lambda data source will receive a payload consisting of the entire [Context](resolver-context-reference.md) object.
+ By disabling the response mapping template, the result of your Lambda invocation will be translated depending on the version of the request mapping template or if the request mapping template is also disabled. 

# Testing and debugging resolvers in AWS AppSync (VTL)
<a name="test-debug-resolvers"></a>

**Note**  
We now primarily support the APPSYNC\$1JS runtime and its documentation. Please consider using the APPSYNC\$1JS runtime and its guides [here](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html).

AWS AppSync executes resolvers on a GraphQL field against a data source. As described in [Resolver mapping template overview](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview), resolvers communicate with data sources by using a templating language. This enables you to customize the behavior and apply logic and conditions before and after communicating with the data source. For an introductory tutorial-style programming guide for writing resolvers, see the [Resolver mapping template programming guide](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide).

To help developers write, test, and debug these resolvers, the AWS AppSync console also provides tools to create a GraphQL request and response with mock data down to the individual field resolver. Additionally, you can perform queries, mutations, and subscriptions in the AWS AppSync console and see a detailed log stream from Amazon CloudWatch of the entire request. This includes results from a data source.

## Testing with mock data
<a name="testing-with-mock-data"></a>

When a GraphQL resolver is invoked, it contains a `context` object that contains information about the request. This includes arguments from a client, identity information, and data from the parent GraphQL field. It also contains the results from the data source, which can be used in the response template. For more information about this structure and the available helper utilities to use when programming, see the [Resolver Mapping Template Context Reference](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference).

When writing or editing a resolver, you can pass a *mock* or *test context* object into the console editor. This enables you to see how both the request and the response templates evaluate without actually running against a data source. For example, you can pass a test `firstname: Shaggy` argument and see how it evaluates when using `$ctx.args.firstname` in your template code. You could also test the evaluation of any utility helpers such as `$util.autoId()` or `util.time.nowISO8601()`.

### Testing resolvers
<a name="test-a-resolver"></a>

This example will use the AWS AppSync console to test resolvers.

1. Sign in to the AWS Management Console and open the [AppSync console](https://console.aws.amazon.com/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Schema**.

1. If you haven't done so already, under the type and next to the field, choose **Attach** to add your resolver.

   For more information on how to build a conplete resolver, see [Configuring resolvers](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html).

   Otherwise, select the resolver that's already in the field.

1. At the top of the **Edit resolver** page, choose **Select test context**, choose **Create new context**.

1. Select a sample context object or populate the JSON manually in the **Execution context** window below.

1. Enter in a **Text context name**.

1. Choose the **Save** button.

1. At the top of the **Edit Resolver** page, choose **Run test**.

For a more practical example, suppose you have an app storing a GraphQL type of `Dog` that uses automatic ID generation for objects and stores them in Amazon DynamoDB. You also want to write some values from the arguments of a GraphQL mutation, and allow only specific users to see a response. The following shows what the schema might look like:

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

When you add a resolver for the `addDog` mutation, you can populate a context object like the following example. The following has arguments from the client of `name` and `age`, and a `username` populated in the `identity` object:

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

You can test this using the following request and response mapping templates:

 **Request Template** 

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "id" : { "S" : "$util.autoId()" }
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

 **Response Template** 

```
#if ($context.identity.username == "Nadia")
  $util.toJson($ctx.result)
#else
  $util.unauthorized()
#end
```

The evaluated template has the data from your test context object and the generated value from `$util.autoId()`. Additionally, if you were to change the `username` to a value other than `Nadia`, the results won’t be returned because the authorization check would fail. For more information about fine grained access control, see [Authorization use cases](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases).

### Testing mapping templates with AWS AppSync's APIs
<a name="testing-with-appsync-api"></a>

You can use the `EvaluateMappingTemplate` API command to remotely test your mapping templates with mocked data. To get started with the command, make sure you have added the `appsync:evaluateMappingTemplate` permission to your policy. For example:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:evaluateMappingTemplate",
            "Resource": "arn:aws:appsync:us-east-1:111122223333:*"
        }
    ]
}
```

------

You can leverage the command by using the [AWS CLI](https://aws.amazon.com/cli/) or [AWS SDKs](https://aws.amazon.com/tools/). For example, take the `Dog` schema and its request/response mapping templates from the previous section. Using the CLI on your local station, save the request template to a file named `request.vtl`, then save the `context` object to a file named `context.json`. From your shell, run the following command:

```
aws appsync evaluate-mapping-template --template file://request.vtl --context file://context.json
```

The command returns the following response:

```
{
  "evaluationResult": "{\n    \"version\" : \"2017-02-28\",\n    \"operation\" : \"PutItem\",\n    \"key\" : {\n        \"id\" : { \"S\" : \"afcb4c85-49f8-40de-8f2b-248949176456\" }\n    },\n    \"attributeValues\" : {\"firstname\":{\"S\":\"Shaggy\"},\"age\":{\"N\":4}}\n}\n"
}
```

The `evaluationResult` contains the results of testing your provided template with the provided `context`. You can also test your templates using the AWS SDKs. Here's an example using the AWS SDK for JavaScript V2: 

```
const AWS = require('aws-sdk')
const client = new AWS.AppSync({ region: 'us-east-2' })

const template = fs.readFileSync('./request.vtl', 'utf8')
const context = fs.readFileSync('./context.json', 'utf8')

client
  .evaluateMappingTemplate({ template, context })
  .promise()
  .then((data) => console.log(data))
```

Using the SDK, you can easily incorporate tests from your favorite test suite to validate your template's behavior. We recommend creating tests using the [Jest Testing Framework](https://jestjs.io/), but any testing suite works. The following snippet shows a hypothetical validation run. Note that we expect the evaluation response to be valid JSON, so we use `JSON.parse` to retrieve JSON from the string response:

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })

test('request correctly calls DynamoDB', async () => {
  const template = fs.readFileSync('./request.vtl', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateMappingTemplate({ template, context }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 This yields the following result:

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.511 s, estimated 2 s
```

## Debugging a live query
<a name="debugging-a-live-query"></a>

There’s no substitute for an end-to-end test and logging to debug a production application. AWS AppSync lets you log errors and full request details using Amazon CloudWatch. Additionally, you can use the AWS AppSync console to test GraphQL queries, mutations, and subscriptions and live stream log data for each request back into the query editor to debug in real time. For subscriptions, the logs display connection-time information.

To perform this, you need to have Amazon CloudWatch logs enabled in advance, as described in [Monitoring and logging](monitoring.md#aws-appsync-monitoring). Next, in the AWS AppSync console, choose the **Queries** tab and then enter a valid GraphQL query. In the lower-right section, click and drag the **Logs** window to open the logs view. At the top of the page, choose the play arrow icon to run your GraphQL query. In a few moments, your full request and response logs for the operation are streamed to this section and you can view then in the console.

# Configuring and using pipeline resolvers in AWS AppSync (VTL)
<a name="pipeline-resolvers"></a>

**Note**  
We now primarily support the APPSYNC\$1JS runtime and its documentation. Please consider using the APPSYNC\$1JS runtime and its guides [here](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html).

AWS AppSync executes resolvers on a GraphQL field. In some cases, applications require executing multiple operations to resolve a single GraphQL field. With pipeline resolvers, developers can now compose operations called Functions and execute them in sequence. Pipeline resolvers are useful for applications that, for instance, require performing an authorization check before fetching data for a field.

A pipeline resolver is composed of a **Before** mapping template, an **After** mapping template, and a list of Functions. Each Function has a **request** and **response** mapping template that it executes against a data source. As a pipeline resolver delegates execution to a list of functions, it is therefore not linked to any data source. Unit resolvers and functions are primitives that execute operations against data sources. See the [Resolver mapping template overview](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) for more information.

## Step 1: Creating a pipeline resolver
<a name="create-a-pipeline-resolver"></a>

In the AWS AppSync console, go to the **Schema** page.

Save the following schema:

```
schema {
    query: Query
    mutation: Mutation
}

type Mutation {
    signUp(input: Signup): User
}

type Query {
    getUser(id: ID!): User
}

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

We are going to wire a pipeline resolver to the **signUp** field on the **Mutation** type. In the **Mutation** type on the right side, choose **Attach** next to the `signUp` mutation field. On the create resolver page, click on **Actions**, then **Update runtime**. Choose `Pipeline Resolver`, then choose `VTL`, then choose **Update**. The page should now show three sections: a **Before mapping template** text area, a **Functions** section, and an **After mapping template** text area.

Our pipeline resolver signs up a user by first validating the email address input and then saving the user in the system. We are going to encapsulate the email validation inside a **validateEmail** function, and the saving of the user inside a **saveUser** function. The **validateEmail** function executes first, and if the email is valid, then the **saveUser** function executes.

The execution flow will be as follow:

1. Mutation.signUp resolver request mapping template

1. validateEmail function

1. saveUser function

1. Mutation.signUp resolver response mapping template

Because we will probably reuse the **validateEmail** function in other resolvers on our API, we want to avoid accessing `$ctx.args` because these will change from one GraphQL field to another. Instead, we can use the `$ctx.stash` to store the email attribute from the `signUp(input: Signup)` input field argument.

**BEFORE** mapping template:

```
## store email input field into a generic email key
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
```

The console provides a default passthrough **AFTER** mapping template that will we use:

```
$util.toJson($ctx.result)
```

Choose **Create** or **Save** to update the resolver.

## Step 2: Creating a function
<a name="create-a-function"></a>

From the pipeline resolver page, in the **Functions** section, click on **Add function**, then **Create new function**. It is also possible to create functions without going through the resolver page; to do this, in the AWS AppSync console, go to the **Functions** page. Choose the **Create function** button. Let’s create a function that checks if an email is valid and comes from a specific domain. If the email is not valid, the function raises an error. Otherwise, it forwards whatever input it was given.

On the new function page, choose **Actions**, then **Update runtime**. Choose `VTL`, then **Update**. Make sure you have created a data source of the **NONE** type. Choose this data source in the **Data source name** list. For **function name**, enter in `validateEmail`. In the **function code** area, overwrite everything with this snippet:

```
#set($valid = $util.matches("^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com", $ctx.stash.email))
#if (!$valid)
    $util.error("$ctx.stash.email is not a valid email.")
#end
{
    "payload": { "email": $util.toJson(${ctx.stash.email}) }
}
```

Paste this into the response mapping template:

```
$util.toJson($ctx.result)
```

Review your changes, then choose **Create**. We just created our **validateEmail** function. Repeat these steps to create the **saveUser** function with the following request and response mapping templates (For the sake of simplicity, we use a **NONE** data source and pretend the user has been saved in the system after the function executes.): 

Request mapping template:

```
## $ctx.prev.result contains the signup input values. We could have also
## used $ctx.args.input.
{
    "payload": $util.toJson($ctx.prev.result)
}
```

Response mapping template:

```
## an id is required so let's add a unique random identifier to the output
$util.qr($ctx.result.put("id", $util.autoId()))
$util.toJson($ctx.result)
```

We just created our **saveUser** function.

## Step 3: Adding a function to a pipeline resolver
<a name="adding-a-function-to-a-pipeline-resolver"></a>

Our functions should have been added automatically to the pipeline resolver we just created. If this wasn't the case, or you created the functions through the **Functions** page, you can click on **Add function** on the resolver page to attach them. Add both the **validateEmail** and **saveUser** functions to the resolver. The **validateEmail** function should be placed before the **saveUser** function. As you add more functions, you can use the **move up** and **move down** options to reorganize the order of execution of your functions. Review your changes, then choose **Save**.

## Step 4: Executing a query
<a name="executing-a-query"></a>

In the AWS AppSync console, go to the **Queries** page. In the explorer, ensure that you're using your mutation. If you aren't, choose `Mutation` in the drop-down list, then choose `+`. Enter the following query:

```
mutation {
  signUp(input: {
    email: "nadia@myvaliddomain.com"
    username: "nadia"
  }) {
    id
    email
  }
}
```

This should return something like:

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "email": "nadia@myvaliddomain.com"
    }
  }
}
```

We have successfully signed up our user and validated the input email using a pipeline resolver. To follow a more complete tutorial focusing on pipeline resolvers, you can go to [Tutorial: Pipeline Resolvers](tutorial-pipeline-resolvers.md#aws-appsync-tutorial-pipeline-resolvers) 