[null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/J8M35G6.jpg", "src": "https://imgur.com/J8M35G6.jpg", "formatted_filename": "J M G"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/mcZ9Z01.jpg", "src": "https://imgur.com/mcZ9Z01.jpg", "formatted_filename": "mcZ Z", "alt_text": "Figure 1"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/WXOmvlL.jpg", "src": "https://imgur.com/WXOmvlL.jpg", "formatted_filename": "WXOmvlL"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/JjchrNz.jpg", "src": "https://imgur.com/JjchrNz.jpg", "formatted_filename": "JjchrNz"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/JC9WEXP.jpg", "src": "https://imgur.com/JC9WEXP.jpg", "formatted_filename": "JC WEXP"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/CvCvAzb.jpg", "src": "https://imgur.com/CvCvAzb.jpg", "formatted_filename": "CvCvAzb"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/5cnYHHT.jpg", "src": "https://imgur.com/5cnYHHT.jpg", "formatted_filename": "cnYHHT"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/RafU8pK.jpg", "src": "https://imgur.com/RafU8pK.jpg", "formatted_filename": "RafU pK"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://i.imgur.com/FUX0oXE.jpg", "src": "https://i.imgur.com/FUX0oXE.jpg", "formatted_filename": "FUX oXE"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/JYS4N9u.jpg", "src": "https://imgur.com/JYS4N9u.jpg", "formatted_filename": "JYS N u"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/3oL7cUM.jpg", "src": "https://imgur.com/3oL7cUM.jpg", "formatted_filename": "oL cUM"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/ZV0WEK1.jpg", "src": "https://imgur.com/ZV0WEK1.jpg", "formatted_filename": "ZV WEK"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/qZkPT5s.jpg", "src": "https://imgur.com/qZkPT5s.jpg", "formatted_filename": "qZkPT s"}, null, {"document_url": "https://tylermcginnis.com/building-serverless-react-graphql-apps-with-aws-appsync/", "unformatted_src": "https://imgur.com/ZI9NvdC.jpg", "src": "https://imgur.com/ZI9NvdC.jpg", "formatted_filename": "ZI NvdC"}, null]
Building Serverless React GraphQL Applications with AWS AppSync

April 5 2018.20 min read.
byNader Dabit

AWS AppSync allows developers to offload the complexity and time involved with building a GraphQL backend and only worry about building their application, and it does so with real-time and offline capabilities.

In this post, we’ll look at how to create a new AppSync GraphQL API & connect it to a React application. We’ll also add mutations, queries, and subscriptions to the application to make the data real-time.

To view the final code for this app, click here 
The application we will be building is a recipe app. Each recipe will have a name, ingredients, and instructions associated with it.

When working with AppSync there are 2 main parts: the client application and the GraphQL API. The client will be our web application, and the API will be the AppSync API hosted on AWS.

We will start by creating the AppSync API, then we’ll create our React application and wire the two together.

Creating the AWS AppSync API

To build the API you will need to have an AWS account. If you do not already have one, you can visit the AWS console and sign up.

The first thing we will need to do is open the AppSync console. To do so, go into the AWS console, click Services, and under Mobile Services you will see AWS AppSync. You can also go there directly by visiting https://console.aws.amazon.com/appsync/.

Click on AWS AppSync under Mobile Services, which will take you the AppSync dashboard. On the top right corner of this dashboard there will be a button that says Create API, click that button to create our new API. Here, give the API a name (I’m calling mine “Recipes”), and leave the Custom Schema template chosen and click Create. In the next screen we will be shown the dashboard of our newly created API. We should see our API URL & Auth mode first, with a getting started section right below. On the left we will see a menu with Schema, Queries, Data Sources, and Settings links. We’ll discuss what these links in this menu do in some of the following steps. Creating the Schema

Now that we have our API created, we need to do the following:

AppSync actually does alot of this for us as we will see in the following steps, the only thing we will need to do is create the schema.

In the left menu, click on Schema.

Now, clear out the commented out code and add the following schema and click Save: Creating resources

Now that the basic schema has been created, we need to a data source as well as add queries, mutations, and subscriptions. We also need resolvers to map the GraphQL request and response between the database and the schema.

AppSync can autogenerate all of this for us. To demonstrate this and create our resources, click on the Create Resources button to the top right of the schema.

Select Recipe as the type.

Now, we should see an area for us to decide the table name, and some additional code that will be added to our schema.

Go ahead and click Create. After this we should see some new items added to our schema. Our schema should now look like this:

Not only was the schema updated, but a table was created in DynamoDB and resolvers were created to map between the schema and the table. We’ll look at the resolvers in just a moment.

In the left menu, you should be able to now click on Data Sources and see the new table that was created. If you ever want to inspect this table, you can click on the table name under Resource and this will take you into the DynamoDB console to view the table.

Testing our API

Let’s test out this data by executing a mutation and then a query.

The mutation we will execute will be createRecipe, and the query will be getRecipe.

In the left menu, click on queries and create then execute the following mutation: If the mutation was successful, you should see the returned id on the right hand side.

Now, if you go back into your data sources, click on the table name, and then view the items tab, you should see the newly created. item.

Next, let’s perform a query on the data that is now in our table. We want to fetch all of the recipes from our API and view them in an array.

Below the mutation, add the following code:

If you now click on the orange play button, you should see a dropdown of the two types of actions that can be performed.

In the dropdown, click on listRecipes to execute the query: You should see the results of the query on the right hand side.


Now that we know that our schema and data source are working correctly, let’s take a look at the resolvers that were created when we created our data source.

Click back to our schema, and look to the right under Data Types.

If you look at these data types, you’ll see that we also have resolvers already created for us for all of our mutations and queries.

Scroll down below Mutation to createRecipe and click on RecipeTable to the right under the Resolver field. Here, we can see the resolver that is associated with the mutation. Resolvers have three parts:

The request mapping template is where the GraphQL request is handled before being handed to the data source, in our case a DynamoDB table.

Mapping templates are written in a templating language called Apache Velocity Templating Language or VTL. AppSync uses VTL to translate GraphQL requests from clients into a request to your data source.

If you are familiar with other programming languages such as JavaScript, C, or Java, VTL should be fairly straightforward.

Let’s take a look at the request mapping template:

The fields are defined as follows:

If you’d like to learn more about how the mapping templates and VTL work, check out the documentation here. I’ve found that spending about an hour going through this documenatation got me to the point where I felt confident enough to start creating more complex custom queries and mutations.

Accessing the $context

You may have noticed that we are accessing a variable called $ctx in the attributeValues and the key fields. $ctx is short for $context and either can be used interchangeably.

The $ctx variable holds all of the contextual information for your resolver invocation. It has the following structure:

Each $ctx field is defined as follows:

To learn more about $context, click here.

Leveraging $util

You may have also noticed the use of the $util variable used in the mapping template.

The $util variable contains general utility methods that make it easier to work with data.

There are multiple $util methods available, inculding a very handy function that allows us to generate ids on the fly: $util.autoId().

To learn more about $util and see all of the available methods, click here.

Building the client side React app

Our API is complete and we can now begin interacting with it from our application!

The dependencies we will be using are Create React App to create our React app, glamor for styling, React Router for routing, and uuid to create unique ids.

For our GraphQL client, we will be using a combination of React Apollo, AWS AppSync, AWS Appsync React, and graphql-tag.

Creating the app and installing dependencies

To get started, let’s create a new React app and install our dependencies:

Next, we need to download the AppSync configuration file that we will be using to hook up our React application with the AppSync API.

We can do this by going into our AppSync dashboard and clicking on the the API name in the left menu, scrolling to the bottom, clicking on Web, and then clicking on Download below the Download the AWS AppSync config file: Download and save this file as src/appsync.js in your recipes application.

Next, let’s take a look at how we will structure our app.

We will need two routes:

Let’s go ahead and create the routes we will need. We’ll also create a Nav component that will serve as the static navigation component for navigating between these two routes:

We will also need queries, mutations, and subscriptions for this app. Let’s create a folder for each of these and a file to hold them:

Wiring up the AppSync client

Next, let’s open index.js and update it with the following code:

The two main things that are happening are:

A. We are creating a new AppSync client and storing it in the client variable, calling new AppSyncClient and passing in the configuration we would like.

We are setting the auth type as API_KEY, which comes from our appsync.js configuration. This can also be set to Amazon Cognito user pools or Amazon Cognito Federated Identities. To learn more about how this configuration works, check out these docs.

B. Here we are using the ApolloProvider from react-apollo to inject the client that we created into our application. By doing this, we now have access to our AppSync client anywhere in our entire application, or any component that is a child of the App component which is the entrypoint to our app.

Rehydrated will wait until the application cache has been read and is ready to use in the app before rendering the app. By default, this just shows some loading text, but this can be configured with our own UI like this if we would like:

Creating the Router

Next, let’s create a basic router with two routes. Open App.js and update it to the following:

As you can see above, we have two routes: / that will render the Recipes component, and /addrecipe which will render the AddRecipe component. We also have a Nav component that’s displayed no matter which route we are currently viewing.

Creating the Nav component

Nav is a pretty basic component that will only have a title and two links, along with some basic styling:

Creating the AddRecipe component and working with mutations

In the AddRecipe.js component we will be interacting with our AppSync client for the first time by performing a mutation to add data (a recipe) to our AppSync API, and a query to create an optimistic response.

Let’s go ahead and create the mutation & query we will be needing.

In src/mutations, create a new file called CreateRecipe.js to hold our GraphQL mutation:

In src/queries, create a new file called ListRecipes.js to hold our GraphQL query:

Let’s take a look at how we will be wiring up the mutation for adding a new recipe.

The way we will be doing this is by wrapping the component that we would like the mutation to interact with, in our case the App component, with the graphql higher order component from Apollo:

The object returned from the props function will be received by the component as props. We declare an onAdd function (received in the App component as this.props.onAdd) that will pass in the object recipe as an argument (recipe will be the new recipe we would like to have created).

The optimisticResponse and update functions provide a way to update the local cache and our UI with the new data without having to wait for the data to get to the database and refresh our local data.

In the update function, we use the ListRecipes query to read and write data to the cache.

In our actual App component, we will call onAdd like this:

Let’s put all of this together with form inputs and some state to create our AddRecipe component: Creating the Recipes component and working with Queries & Subscriptions

The recipes component will be using the ListRecipes query to get the array of recipes from the database, and will also be using a subscription to listen for new data added to the API, subscribe to these changes, and update our local data when these changes happen.

The last file we need to create is the subscription to handle this functionality.

In src/subscriptions, create a new file called NewRecipeSubscription.js:

Let’s take a look at how we will be wiring up the query & subscription to the component:

Like in the mutation example, the object returned from the props function will be available in the component as this.props. We declare two things:

The Recipes component will receive the array of recipes as props, map over them, and display them in the UI.

Let’s take a look at how all of this looks wired up together with some styling: Now, start the app with npm start and you should be able to create and view recipes.

That’s it! You have just created your first React + AppSync application.


AWS AppSync is extremely powerful, and in this tutorial we’ve just scratched the surface.

In addition to DynamoDB, AppSync also supports ElasticSearch & Lambda functions out of the box.

To continue learning and taking advantage of what it has to offer, I would focus on learning how the mapping templates work in depth.

Then, I would look at Authorization, possibly utilizing AWS Amplify or some other Authentication provider.


Liked this post? Share it 🕺

Listen, I get it, newsletters are the worst.

This one is different though.

The Socials

The Newsletter