In these tutorials, I’ll show you how to create and interact with a GraphQL database using AWS AppSync and React Native. This app will have real-time and offline functionality, something we get out of the box with AppSync. In this post we’ll get started by setting up the back-end with AppSync.
A great thing about AppSync is that it uses GraphQL—an open standard and a powerful new paradigm for the web and mobile back-end. If you want to learn more about GraphQL, how it differs from REST APIs, and how it can make your job as an app developer easier, check out some of our GraphQL content here on Envato Tuts+.
-
What Is GraphQL?
-
New Course: Build APIs With GraphQL
In these posts, we will be building a travel app called Cities. Have you ever been watching a show on your favorite food channel and seen an awesome food truck, or spoken to a friend that just got back from a trip and was really excited about the Owl Bar she visited? Well fret no more, we will be building an app for you to keep up with all of those cool places you want to visit, as well as the cities where they are located.
This app will demonstrate and implement all of the functionality you will need to build a real-world, full-stack React Native and GraphQL application.
Check out the example project’s GitHub repo to see the completed app and to follow along.
About the Technology
AppSync offers an easy way to get up and running with a scalable, real-time GraphQL server without having to create and maintain it all on your own.
Within the AppSync console, we will do everything from creating our GraphQL schema to provisioning our database and resolvers. The console also has Graphiql set up so we can test and query our database without any extra setup.
We will implement this configuration on our client, which will give us a seamless way to interact with our GraphQL endpoint!
AppSync will allow you to use one of three resolver types right out of the box: DynamoDB, Elasticsearch, or AWS Lambda. We will be using DynamoDB in this tutorial.
Getting Started
The first thing we need to do is create a new AppSync application and add our basic Schema.
Our application will need to store two sets of data—a list of cities and a list of locations that we will associate with individual cities within the list—so our schema will have two main data types (City & Location).
To get started with AppSync, go to the AWS Console and choose AWS AppSync within the Services dropdown menu.
Once we are in the in the AppSync dashboard, we need to click the Create API button:
Now, we will have the option to give the application a name (I’m calling mine TravelApp), and choose the type of schema (custom or sample). We will choose the custom schema option, and then click Create.
The next screen will be the dashboard for the new application. We’ll see some useful information right away, including the URL for our app as well as the authorization mode. On the left side, you will see a few links: Schema, Queries, DataSources, and Settings.
Have a look around at the options here before you move on to the next step.
Creating a Schema and Provisioning a Data Source
The next thing we will do is create the schema we would like to use for our application. Again, the schema will have a City and Location type to start off.
From the editor, click on the the Schema tab, and create the following basic schema with two types and one query and click Save:
type City { id: ID! name: String! country: String! locations: [Location] } type Location { id: ID! cityId: ID! name: String! info: String } type Query { fetchCity(id: ID!): City } schema { query: Query }
Attach the Schema to a Database
Now that we have a basic schema created, we need to attach this schema to a database!
AppSync makes this extremely easy. Click the Create Resources button at the right of the screen. We will need two database tables: one to hold our cities, and another to hold our locations.
Choose City, accept all of the defaults, and click Create. You’ll notice that this will automatically add some useful queries, mutations, and subscriptions to our schema!
Go ahead and do the same for the Location resource. We have now successfully created two database tables that go along with our schema, and also some basic queries, mutations, subscriptions, and resolvers that will map the schema to those tables (we’ll explore the resolvers in the next section).
Let’s now take a look at what was created. In the left-hand menu, click on Data Sources.
You should now see the two data sources we just created!
Run Some Test Queries
Now that we have new Mutations and Subscriptions created in our Schema, let’s add them to our Schema definition.
To do so, scroll to the bottom of the Schema and update the schema definition to the following:
schema { query: Query mutation: Mutation subscription: Subscription }
Next, we can test everything out by creating a mutation and then a query. In the Queries tab, create the following mutation:
mutation createCity { createCity( input: { id: "00001" name: "Seattle" country: "USA" } ) { id } }
This will add a record for Seattle to the city table, with an id of 00001.
Then, create a query to retrieve that data:
query getCity { getCity(id: "00001") { id name country } }
When you click the orange play button, you can choose to execute the createCity
mutation or the getCity
query. Run them both and you should see the Seattle city data retrieved and output on the right side of the screen.
If you want to see how this data is represented in the database, you can explore the DynamoDB city table linked from the Data Sources tab.
Resolver Mapping Templates
You may be wondering how the query maps to the database so seamlessly. The answer is resolvers!
If you look at the right-hand side of the AppSync dashboard’s Schema tab, you’ll see a section titled Data Types. This lists all of the data types within our Schema. To the right of each field, we see a heading labeled Resolver.
Resolvers are basically the interface between the schema and the database that we are currently using. We can use resolvers for everything from basic retrieval of items to complex actions like fine-grained access control.
Resolvers are written in a DSL called Velocity Templating Language (VTL). AppSync will automatically provision basic resolvers upon datasource creation, but they are highly configurable. At this point, we don’t really need to change a lot in our resolvers, but let’s take a look at three of the main types of resolvers you’ll probably need to work with in the real world. These are connected to the following basic operations:
- Getting a single item by its id
- Getting a list of items
- Putting an item into the database
Getting an Item by Id
In the Data Types tab, next to the schema definitions, find getCity
under Query, and click on CityTable.
This should take you to the resolver configuration screen. From this screen, you’ll see that there are three main pieces to a resolver:
- Data source name
- Request mapping template
- Response mapping template
The data source is the table that you would like to interact with.
The request mapping template describes how the database will handle the request.
Here, you can write your own mapping template or choose from a selection of prepopulated templates for basic actions like getting or putting an item, among other things.
Here, you see the template for getting an item.
The response mapping template describes how to handle the response from the database.
In our response template, we are basically just returning the context.result
and wrapping it in the $utils.toJson
utility function. This is just one of many helper utils that will abstract away some of the VTL boilerplate. See the complete list of utility methods in the official documentation.
As your application becomes more complex, the key to getting proficient at AppSync is getting comfortable with working with these mapping templates. It took me a few hours to wrap my head around how it all worked, but after experimenting with it for a short while I could see how powerful it is.
We don’t have space here to get into all the details of resolver mapping templates, but you can check out the Resolver Resolver Mapping Template Reference and Mapping Template Context Reference to learn more about them.
For now, we’ll move on and complete our schema.
Finalizing the AppSync Configuration
We have completed our schema, but we have one last step before we can begin interacting with our new GraphQL endpoint from our React Native application!
Because we are going to be storing all of our locations in one table but querying them based on the city we are currently viewing, we will need to create a secondary index to allow us to efficiently query locations with a particular cityId
.
To create a secondary index, go to Data Sources and click on the Location Table hyperlink.
This should take you to the DynamoDB table view for the Location Table. Here, click the Indexes tab and create a new index with a partition key of cityId
.
You can lower the read and write capacity units to 1 for the purposes of this tutorial.
Next, we need to update our listLocations
query to accept this cityId
as an argument, so update the query for listLocations
to the following:
type Query { // all previous queries omitted listLocations(cityId: ID!, first: Int, after: String): LocationConnection }
Now, we need to update our listLocations
resolver to use this new cityId
index! Remember, we really only want listLocations
to return an array of locations for the city that we are looking at, so the listLocations
resolver will take the cityId
as a parameter and only return locations for that city.
To get this working, let’s update the request mapping template for listLocations
to be the following:
{ "version": "2017-02-28", "operation": "Query", "index": "cityId-index", "query": { "expression": "cityId = :cityId", "expressionValues": { ":cityId": { "S": "$ctx.args.cityId" } } }, "limit": #if($context.arguments.limit) $context.arguments.limit #else 10 #end, "nextToken": #if($context.arguments.nextToken) "$context.arguments.nextToken" #else null #end }
Conclusion
In this tutorial, we’ve created the back-end for a React Native app with its own GraphQL endpoint. We also looked at how to create and update resolvers and work with the AppSync schema.
Now that we are finished configuring everything in the console, we can go ahead and create our React Native client! Stay tuned for the next post, where I dive into the React Native mobile app and show you how to hook React Native up to AppSync.
In the meantime, check out some of our other posts about React Native app development!
-
React NativeAnimate Your React Native App
-
Mobile DevelopmentTools for React Native Development
-
React NativeGetting Started With a React Native App Template
-
React6 Cutting-Edge React Courses
Some images used with credit from Amazon Web Services, Inc.
Powered by WPeMatico