What are Resolvers in AppSync and how they work

(Read this article on the blog) Resolvers in GraphQL Resolvers provide the implementation for how AppSync processes queries and mutations. They connect the GraphQL schema, the abstract definition of the API, and the services that provide the data, such as a database or a Lambda function. In practice, most of AppSync development is spent writing […]

(Read this article on the blog)

Resolvers in GraphQL

Resolvers provide the implementation for how AppSync processes queries and mutations. They connect the GraphQL schema, the abstract definition of the
API, and the services that provide the data, such as a database or a Lambda function. In practice, most of AppSync development is spent writing resolvers.

Each resolver is for a field in the schema. And fields are defined for types. When a query requests a field, the resolver configured for that field
runs and returns the appropriate data.

Let’s see an example!

There is a Query type and a test field that is a String. In GraphQL, it looks like this:

type Query {
	test: String
}

A query then can request the test field:

query MyQuery {
	test
}

In the response, the field will be a String, as defined in the schema:

{
	"data": {
		"test": "test response"
	}
}

Where does this value comes from? That’s what the resolver for the Query.test field defines. It can come from a database query, a Lambda function, an HTTP
call, or some other place. The important thing is the response contains the string that AppSync will return to the query.

query MyQuery {test}”data”: {“test”: “test response”}Query.testQuery.testprocessrequestresponse”test response”AppSyncResolversDatabasesSimple query

Nested fields

What if a field returns a type instead of a scalar? For example, the item field returns an Item in this schema:

type Item {
	field1: String
}

type Query {
	item: Item
}

A query can then request the fields of the returned type:

query MyQuery {
	item {
		field1
	}
}

What happens here?

AppSync resolves fields recursively. It starts with the outermost field and moves down after that. Because of this, the first part is not different than
before, as it resolves Query.item first.

The Query.item returns some response. For AppSync, it does not matter what exactly. But after that it moves down one level to Item.field1. The
response needs to be a String and that will be the response for that field.

So, where is the result of the Query.item resolver used? The Item.field1 resolver gets that as the source object in the $context. In
practice, most of the time the outer resolver returns an object and the inner resolver transforms part of it.

query MyQuery {item {field1}t}item {field1}”data”: {“item”: {“field1”: “test response”}t}Query.itemQuery.itemItem.field1Item.field1processprocessrequestresponseobjectobjectrequestresponse”test response”AppSyncResolversDatabasesNested query

Why this structure is great

In a query, nesting can go to any depth, making it possible for the client to define exactly what it needs and AppSync does the rest. This does not requires
any fewer database calls, but instead of having 1 backend call (between the client and AppSync) for each database query, it needs only 1 for the whole query. In
practice, this drastically reduces the latency users experience.

Only 1 request is neededbrowserAPIdbGraphQL query for users and todoslist usersusersget todos for user 1user1 todosget todos for user 2user2 todosusers and todos

As a developer, you need to think about how to generate the response for individual fields and not for individual queries. You don’t need to know
whether the client will need nested data or not. When a client sends a query, AppSync will run the necessary resolvers and provide the correct response with
only the data the client needs.

Source: Advanced Web Machinery