Testing and debugging resolvers in AWS AppSync (VTL)
Note
We now primarily support the APPSYNC_JS runtime and its documentation. Please consider using the APPSYNC_JS runtime and its guides here.
AWS AppSync executes resolvers on a GraphQL field against a data source. As described in Resolver mapping template 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.
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
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.
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
This example will use the AWS AppSync console to test resolvers.
-
Sign in to the AWS Management Console and open the AppSync console
. -
In the APIs dashboard, choose your GraphQL API.
-
In the Sidebar, choose Schema.
-
-
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.
Otherwise, select the resolver that's already in the field.
-
At the top of the Edit resolver page, choose Select test context, choose Create new context.
-
Select a sample context object or populate the JSON manually in the Execution context window below.
-
Enter in a Text context name.
-
Choose the Save button.
-
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.
Testing mapping templates with AWS AppSync's APIs
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:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "appsync:evaluateMappingTemplate", "Resource": "arn:aws:appsync:<region>:<account>:*" } ] }
You can leverage the command by using the AWS CLIDog
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 FrameworkJSON.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
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. 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.