In this module you'll use AWS AppSync to build a GraphQL API to find more information about the rides you have taken so far. In a subsequent module you will then modify our web application to add the ride history page which will query this API.
In the [Serverless Backend][serverless-backend] module you created a Lambda function that stored data in a DynamoDB bucket. Then in the RESTful APIs module you put Amazon API Gatewway infront of the Lambda function so you could connect it to your web application. Every time that you request a ride through that API, the Lambda function stores the data. Now, let's get that data out and present it as ride history.
GraphQL provides a robust query language API that works well with web and mobile based applications. AWS AppSync has the ability to put a GraphQL API infront of many different backends, including: AWS DynamoDB, AWS ElasticSearch Service, Amazon RDS Aurora, and AWS Lambda functions. The GraphQL API you will build here will allow you to return all rides, information about rides by their ID, and information about the unicorns that served your ride.
❗ Ensure you've completed the RESTful APIs step before beginning this module.
Each of the following sections provides an implementation overview and detailed, step-by-step instructions. The overview should provide enough context for you to complete the implementation if you're already familiar with the AWS Management Console or you want to explore the services yourself without following a walkthrough.
Use the AWS AppSync console to create a new GraphQL API. Call your API RidesHistory
. Import the DynamoDB database created in the [Serverless Backend][serverless-backend] module and then create an additional query for getting all rides by a certain unicorn.
✅ Step-by-step directions
-
Go to the AWS AppSync Console.
-
Choose Create API.
-
Select Import DynamoDB table and click Start.
-
Select the Region of your table and enter its Table name. Leave New Role selected. Click Import.
-
AppSync will only detect the Primary Key which was set for your DynamoDB table, but you'll want to map the rest of the data saved by the Lambda function for each ride. You can find what the fields are by looking at an item from your table:
- Go to the Amazon DymamoDB console in a new browser tab or window.
- From the left navigation, select Tables.
- Select the table you created earlier (it should be
Rides
). - Select the Items tab and then select a ride by its
RideId
. - In the pop up window that opens, select Text and check
DynamoDB JSON
. - Record the JSON created here into a scratchpad so that you can refer to it later. The JSON contains the attribute name, type, and data.
- Select Cancel to close the popup without modifying the item.
-
Back in the AppSync console, configure the data model by adding fields that represent all off the top level item attributes recorded from DynamoDB. The items with type
S
areStrings
,M
areJSON Object, Array, or Value
. Check the box forRequired
for all records. -
Click Create.
-
Name the API
RidesHistory
and clickCreate
.
AWS AppSync has created a base GraphQL schema that contains basic functionality for our API. We could use it to create and delete items from out database, but we're only interested in retrieving data in this module. Expand on what was created by adding a query to find rides based on the unicorn that serviced them. The DynamoDB table currently has no indexes on any other attributes and so you will need to create a SCAN request filtered by UnicornName.
Create a new query getRidesByUnicornName
that retrieves the ride information based on the UnicornName
.
✅ Step-by-step directions
-
While in the AWS AppSync Console in your
RidesHistory
API, select Schema. -
In the Schema editor modify the Query object to add a new query:
getRidesByUnicornName(UnicornName: String, limit: Int, nextToken: String): RidesConnection
Such that the final object contains 3 queries:
type Query { getRides(RideId: String!): Rides getRidesByUnicornName(UnicornName: String, limit: Int, nextToken: String): RidesConnection listRides(filter: TableRidesFilterInput, limit: Int, nextToken: String): RidesConnection }
-
Click Save Schema>
-
Under Resolvers find the Query section and select Attach next to the new query you just created.
-
On the Create new Resolver page, select the the
Rides
Data source. -
In the Configure the request mapping template. panel, from the drop down select Simple Query with Pagination
-
In the JSON created, replace the
operation
withScan
and thequery
withfilter
for the object that contains expression attributes. -
In the
filter
object, replace every instance ofid
withUnicornName
.- The final JSON for the request mapping template should look like this:
{ "version" : "2017-02-28", "operation" : "Scan", "filter" : { ## Provide a query expression. ** "expression": "UnicornName = :UnicornName", "expressionValues" : { ":UnicornName" : { "S" : "${ctx.args.UnicornName}" } } }, ## Add 'limit' and 'nextToken' arguments to this field in your schema to implement pagination. ** "limit": $util.defaultIfNull(${ctx.args.limit}, 20), "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null)) }
-
In the Configure the response mapping template. panel, from the drop down select Return paginated results.
- The final JSON for the response mapping template should look like this:
{ "items": $util.toJson($ctx.result.items), "nextToken": $util.toJson($util.defaultIfNullOrBlank($context.result.nextToken, null)) }
-
At the top of the page select Save Resolver.
AWS AppSync supports using Amazon Cognito user pools to support user authorization of requests. Configure your GraphQL API to use the user pool that you created in the User Management module earlier.
Configure the AppSync GraphQL API to use the WildRydes
user pool as an authorizer.
✅ Step-by-step directions
-
While in the AWS AppSync Console in your
RidesHistory
API, select Settings. -
Under Authorization type select Amazon Cognito User Pool.
-
Under User Pool configuration select the region of your user pool and then select the user pool created earlier. Lastly, select ALLOW as the default action.
-
At the bottom of the page, select Save.
The AWS AppSync Console contains a helpful query tool that allows you to test out the queries you've created, even allowing you to authenticate with Amazon Cognito from it.
✅ Step-by-step directions
-
While in the AWS AppSync Console in your
RidesHistory
API, select Queries. -
Select Login with User Pools*
-
In the Login with Cognito User Pools popup, for
ClientId
enter theappid
saved earlier. -
Now you need to login with the user you created earlier in the User Management module. One thing to note is that in Cognito your username is different than your email. You'll need to head to the Cognito Console to find the user name for your created user:
- Go to the [Amazon Cognito Console][cognito-console]
- Select Manage User Pools
- Select the user pool created earlier WildRydes
- From the left navigation, select Users and groups
- Make note of the username shown
-
Login with your username and password as set earlier.
You should now be able to execute the queries listed. First, remove the
Mutation
so you don't accidentally create records using the GraphQL interface. -
Remove the JSON object for the
mutation createRides
. -
Click on the Play arrow button in the top of the page. This will execute the
query listRides
query returning all of the data from the DynamoDB table:{ "data": { "listRides": { "items": [ { "RideId": "MeQtpZtYg4GxKpXK6-FwEA", "RequestTime": "2019-05-01T16:39:46.909Z", "Unicorn": "{\"Color\":\"White\",\"Gender\":\"Male\",\"Name\":\"Shadowfax\"}", "UnicornName": "Shadowfax", "User": "munns-at-amazon.com" }, { "RideId": "rKVp3qNg5w056Ei3k_xQTg", ...
Make a note of the
RideId
for one of the rides displayed. -
In the query editor, create a additional query for the defined
getRides
query in your schema. ThegetRides
query takes a single filter argumentRideId
. You can return whatever attributes you would like:query getRides { getRides(RideId: "MeQtpZtYg4GxKpXK6-FwEA"){ RideId UnicornName } }
-
Click on the Play arrow button in the top of the page and select
getRides
from the new drop down that pops up. On the right you should see the results of the query:{ "data": { "getRides": { "RideId": "MeQtpZtYg4GxKpXK6-FwEA", "UnicornName": "Shadowfax" } } }
-
In the query editor, create a additional query for the defined
getRidesByUnicornName
query in created previously in the schema. ThegetRidesByUnicornName
query also takes a single argument ofUnicornName
and returns a type ofitems
that can contain whatever attributes you would like to return. Set the UnicornName to a name seen in the output of either of the two previous queries:query getRidesByUnicornName { getRidesByUnicornName(UnicornName: "Shadowfax"){ items { RideId Unicorn UnicornName RequestTime } } }
-
Execute this query from the Play drop down and you should now see all rides that were performed by the named unicorn provided. If you only have a single ride by this unicorn explore testing the query using a differnt UnicornName. Note that if you have very few saved rides, you might need to go into the
/rides.html
interface on the web application and generate more rides.{ "data": { "getRidesByUnicornName": { "items": [ { "RideId": "MeQtpZtYg4GxKpXK6-FwEA", "Unicorn": "{\"Color\":\"White\",\"Gender\":\"Male\",\"Name\":\"Shadowfax\"}", "UnicornName": "Shadowfax", "RequestTime": "2019-05-01T16:39:46.909Z" }, { "RideId": "c4gr5VI0UfqUKCg6XgHFzQ", "Unicorn": "{\"Color\":\"White\",\"Gender\":\"Male\",\"Name\":\"Shadowfax\"}", "UnicornName": "Shadowfax", "RequestTime": "2019-05-01T18:51:14.597Z" }, ...
You've completed the testing of your AWS AppSync based GraphQL API!
🔑 AWS AppSync simplifies application development by letting you create a flexible API to securely access, manipulate, and combine data from one or more data sources. AppSync is a managed service that uses GraphQL to make it easy for applications to get exactly the data they need.
🔧 In this module you've created an AppSync API and connected it to our DynamoDB database created in an earlier module. You then set the authorization mechanism to the same that we are using for our REST API and web application meaning you'll have a unified way across these 3 different aspects of the application.
✅ After you have successfully tested your new function using the Lambda console, you can move on to the next module, Building the History page.