In this tutorial, you are going to learn how you can execute queries and mutations in a Lambda function on an AppSync GraphQL API. We are going to use the Amplify framework to generate our code, but the solutions here work whether you use Amplify, or Serverless or something else.
Do you even have a backend if you can only modify your database from your client side? There might be operations that you want to prohibit your users from doing. A malicious user might be able to abuse your client-side code. The fix is to have your server manipulate your database, too ππ».
After I read Nader' Dabit's excellent tutorial "Lambda Function GraphQL Resolvers", I wanted to know how I could modify my existing DynamoDB backend from a Lambda function. (Nader only shows how to generate a new database.) When I finally found a solution, I found out that modifying your DynamoDB directly comes with a significant disadvantage: If you have subscriptions or pipeline resolvers set up for your AppSync API they are ignored, and you will NOT trigger them. I needed to find a way to use AppSync from Lambda.
This guide covers how you can access your AppSync API from a Lambda function. We are going to use Amplify to generate the resources, and we are going to use the AppSync client and console to execute the queries and tweak our schemas. I'll leave your client-side code up to you, and we'll focus on the Amplify, AppSync and Lambda code.
Here is an overview of the steps.
Create a Lambda function, which uses the AppSync client to perform GraphQL operations. Use polyfills and install all necessary dependencies.
Ensure the Lambda function has the right execution policy.
Use AppSync's multi auth to allow both requests that are signed by Amazon Cognito User Pools as well as requests that are signed using Amazon's IAM. This way, both the client and the server (aka. the Lambda function) will be authenticated and can have different CRUD permissions.
Note: You want to avoid hardcoding user credentials in your Lambda function. It is best practice for a Lambda function to use an IAM policy on its execution role to interact with a destination service, which is why we take the approach described above.
Let's do it π. Start by initializing your Amplify project.
The first category we are going to add is authentication.
Secondly, we need to add the GraphQL endpoint. This will also generate a DynamoDB for you.
And here is how you want to edit that schema.
We create a model for the todos, which will create a DynamoDB table. The owner of the todos has full CRUD permissions for the todos. We'll later modify this in the Amplify console. Keep in mind: whenever you push changes from Amplify, it will overwrite the work that you did in the console. Remember to add the necessary directives after each push. If this doesn't make sense to you, keep reading. It will make sense soon. I just wanted to get this in your head as early as possible.
Commit your changes to the cloud.
Now, we want to add the Lambda function.
(If you already have a Lambda function update it using amplify update function because the latest version of the CLI will auto-generate the necessary environment variables and policies.) Modify your Lambda function to reflect the following.
Remember to run npm install from the function's src directory if you want to test it locally. Furthermore, you need to create a file at src/graphql.js which contains the query.
Lastly, add the function to a REST API.
Push your changes. Subsequently, visit your AppSync console, choose your API and click on "Schema". Scroll down until you see your Query or Mutation. I want to perform the listTodos query in Lambda, so I grant access to it using both @aws_iam and @aws_cognito_user_pools.
You can use the auth directive's on a per field basis like demonstrated above or you can do it on each type to give all its attributes the directives (type Query @aws_iam @aws_cognito_user_pools {). ModelTodoConnection will also need these permissions because listTodos returns it.
Remember: what you modify in the console will be overwritten every time you push changes to this API
Hit save, and you are done π₯. You should now be able to access the function from your client. Here is how you do that using Amplify in JavaScript.
If you set up your schema the same way I did and created some todos, notice how the items array that you get back is empty. That's because the todos are filtered in AppSync's .vtl template. If you don't know what .vtl templates are and how AppSync uses them as resolver templates for your GraphQL requests, you might want to read "Query More Items Using Scans in AWS Amplify" and "Creating GraphQL Batch Operations for AWS Amplify". In these two tutorials, I explain what .vtl templates are and you are going to learn how you can write your own. Then you should be able to write a custom query and its resolver so that you get some items back.
Summary
We polyfilled some functions which the AppSync client needs and configured it alongside the aws-sdk to perform GraphQL operations from our Lambda function. We ensured the Lambda function has the necessary permissions by tweaking our GraphQL schema.
If you are using Amplify, take a look at this PR. It will bring AppSync's capability to support multiple authorization types to GraphQL transform. If it's already merged check out my other blog posts because I'll probably have written a guide on how to use that directive.
Learn senior fullstack secrets
Subscribe to my newsletter for weekly updates on new videos, articles, and courses. You'll also get exclusive bonus content and discounts.