Amplify GraphQL Lambda @function Resolvers

Isaac
4 min readFeb 14, 2021

Okay, I get why AppSync uses Velocity (VTL) as their resolvers for DynamoDB, being the top NoSQL is no easy feat. However customization can be a nightmare if you don’t have the background or time to learn Velocity.

Traditional AWS AppSync Resolver

And while Amplify AppSync API has lots of integrated GraphQL (Schema Definition Language) SDL modeling resources for developing a fully supported back-end with the help of AWS CloudFormation, you still have limitations with regards to Authentication Logic, Business Logic, or some other Real-Time Logic applied to your Data Source.

The Introduction to Lambda Resolvers

There are multiple approaches to implementing a lambda resolver with your AWS AppSync API, one most notably is the original lambda resolver add-on where a Lambda function is either added post- or pre-DataSource.

Traditional Pre/Post Resolver Pipeline with Lambda Configuration

Though this process requires integrating lambda into the VTL templates, which we were hoping to avoid.

Direct Lambda Resolver

With the release of the direct lambda resolver for AWS AppSync API, Amplify took this as an opportunity to create an additional GraphQL SDL implementation known as @function.

Direct Lambda Resolver Pipeline

For our use case, authentication was our primary cause for using lambda resolvers as you will see why. Authentication can be very useful especially if your model is simple, however ours was not and required a separate authentication logic.

An example of a simple @auth use case:

If your not familiar with the @auth please read the documentation. The following above automatically creates VTL resolvers for this type @model.

  1. The first auth rule states any resource role with an AppSync — IAM permission can invoke this type @model.

2. The second auth rule states any cognito group ‘management’ has full CRUD (create, read, update, delete) access to the type @model.

3. The third auth rule states any cognito group ‘sales’ has CRU (create, read, update) access to the type @model.

If you are using a separate cognito user pool for actual customers please add it to the AWS AppSync Console settings page

4. The fourth auth rules states that any cognito user id also known as ‘sub’ matches the type item string ‘id’ has access to read and update its own table item by definition of owner. This assumes you created a Customer Item based on the cognito created id.

However this is not an ideal authentication framework for this type @model since all groups and IAM users can view ‘ssn’ (social security number), and the owner can view the ‘internal comment’. Since Privacy issues are a concern we must now consider implementing field level authentication.

Field level @auth overwrites the parent @auth model, thus all relevant rules must be applied to each field.

We’re all done then right? Not quite, in most cases you will have far more sensitive data for either the Customer pool, Management/Sales group, and IAM Resource Role. And since VTL resolvers (request mapping templates) are limited to 64 kb in size, you may be in a pickle if you have more groups and/or more sensitive type items. This was our case, since we ran over 100 kb in resolver space we needed another solution.

Thus came the @function.

The @function became useful for our use case since we no longer had to rely on field level @auth.

Notice how we removed the @auth rule from the parent type @model, and replaced the ‘ssn’ type item string @auth field with just an IAM rule, thus allowing only resources with the IAM access to this ‘ssn’ type item string.

We also add a type Query and type Mutation called “user” and “editUser” respectively. This will be our interface between the Customer and AppSync. Also we included the @function with lambda function ‘customerResolver’, and auth rules allowing any authenticated user access to this AppSync API.

Prior to adding @function you must create a lambda function using:

The -${env} depends on the amplify back-end name.
amplify add function

Following the @function tutorial and the Calling AppSync from Lambda tutorial, integrating AppSync into your lambda function is straight forward.

apiRequest.js

graphql.js

resolvers.js

index.js

There you have it! From the customer front-end they can execute GraphQL operations:

const {data} = await API.graphqlOperation(user);
console.log(data.user);

Notice how ‘id’ is not needed since AppSync sends the cognito user id via ‘event.identity.claim’ directly to the lambda resolver.

let ssn = '123-45-6789';
const {data} = await API.graphql(graphqlOperation(
editUser, {ssn: ssn}
));
console.log(data.editUser);

Chaining Lambda Resolvers

Chaining lambda resolvers deserves an article of its own, but to get straight to the point, you can use multiple lambda resolvers sequentially by passing the I/O of the resolver with the prev key of the event parameter.

--

--

Isaac

M.S. Electrical Engineer, Working as a Software Developer mainly with AWS.