AWS AppSync: Conditional Lambda Resolvers Using the Info Context

Robert Bulmer
The Startup
Published in
3 min readSep 1, 2020

AWS AppSync

AppSync is a managed GraphQL service offered by Amazon Web Services and can be used to build scalable enterprise APIs. A typical AppSync solution consists of small resolvers that can be combined to access various data sources such as databases, HTTP APIs or AWS Lambda.

Introduction

In this example, I will be talking about using AWS AppSync with AWS Lambda data sources and one of the challenges I have come across while developing enterprise scale solutions with these technologies.

Each Lambda resolver you have in a particular request triggers an invocation. The problem comes with having nested resolvers where you only request data from the nested Lambda rather than the parent Lambda. As a result you will cause several invocations, incur cost and resource for the first Lambda without needing to.

If you’re running enterprise serverless it is important to consider the architecture to reduce the amount of compute where possible and lower the risk of hitting limits imposed by AWS.

Thankfully, AWS released an AppSync update in Feb 2020 giving us access to the context info object so we can mitigate this issue. Read more here.

Let’s dive in! 💥

Say you have a GraphQL endpoint and schema to retrieve a typical blog post:

type Post{
id: ID!
title: String!
content: String!
image: ImageData!
}
type ImageData{
id: ID!
postId: ID!
path: String!
tags: String
}
type Query{
getPost(id: ID!): Post!
}

Using GraphQL, your query could look like:

query GetPost{
getPost(id: $id){
title
content
image{
path
tags
}
}
}

Suppose in our setup we keep the image data separate from the post data, now each entity will have its own AppSync resolver that links off to a Lambda function and effectively running the above query invokes two Lambdas; getPostLambda and getImageDataLambda. Each of the resolvers request functions look something like:

{
"version": "2017-02-28",
"operation": "Invoke",
"payload": {
"postId": "$ctx.args.id",
"requestId": "$ctx.stash.requestId",
}
}

Now…

90% of the time that’s great! the getPostLambda retrieves title and content from a data store or external service and the getImageDataLambda returns the image data from another.

Suppose we use the power of GraphQL a little bit further, and only request the image data i.e.

query GetPost{
getPost(id: $id){
image{
path
tags
}
}
}

After running the above query, we’ll see two Lambda invocations and importantly, the getPostLambda gets executed and returns with a bunch of data that we do not need… Oh dear!

The fix; Context.Info ✅

We can skip the first lambda execution by inspecting the Context Info which contains information about the GraphQL request that has been made.

Inside the Info object we can inspect the “selectionSetList” property that gives us the fields that the user/query has requested. We can then take that list and use one of the inbuilt AppSync utility functions to determine whether we need fetch data from the data store or just simply return the Id for the following nested resolver(s):

#set( $postProperties = ['title', 'content'])#set( $invokeLambda = $util.list.copyAndRetainAll($ctx.info.selectionSetList, $postProperties).size() > 0 )                                            

#if( $invokeLambda )
{
"version": "2017-02-28",
"operation": "Invoke",
"payload": {
"postId": "$ctx.args.id",
"requestId": "$ctx.stash.requestId",
}
}
#else
#return({
"id": "$ctx.args.id"
})
#end

And there you have it, a conditional resolver that only invokes the getPostLambda if the user requests one or more fields on “post”, otherwise save cost, time and resources by simply returning the post id to the following resolver.

✏️ Find more infomation on the AppSync Context Object here: https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html

Hope this helps! 🚀

Reach me on linkedIn here: https://www.linkedin.com/in/robertbulmer/

--

--

Robert Bulmer
The Startup

Architech Insights | Serverless Engineer/Architect UK — Certified SA and DevOps Pro | AWS Community Builder! 🚀