Creating Asynchronous Serverless APIs with AWS AppSync

Follow these steps to create an AWS AppSync API that connects to a React client-side application using the new AWS Amplify CLI

With the release of the new AWS Amplify CLI, developers now have the ability to scaffold AWS AppSync GraphQL APIs from the command line.

In this post, we’ll learn how to use the CLI to create an AWS AppSync API, as well as how to connect your new API to a client-side web or mobile application.
The CLI can automatically create a fully functional GraphQL API including datasources, resolvers, & additional schema for mutations, subscriptions, & queries. We can also update & delete the schema, datasources, & resolvers in our API directly from our local environment.

Amplify GraphQL Transform We also have the ability to add powerful features such as Elasticsearch, user authorization, & data relations using the Amplify GraphQL Transformlibrary directly from the CLI in our local environment.

Amplify GraphQL Transform is a library for simplifying the process of developing, deploying, and maintaining GraphQL APIs. With it you define your API using the GraphQL Schema Definition Language (SDL) and then pass it to the library where it is transformed and implements your API’s data model in AWS AppSync.
While the library comes with transformers to do most of the work you would need to build a typical API, you can also even write your own GraphQL Transformer.

For example, if we wanted to scaffold out a GraphQL API that created a data-source, resolvers, schema, & then streamed all data to Elasticsearch we could create the following type & push it up using the AWS Amplify CLI:
type Pet @model @searchable { id: ID! name: String! description: String }

In the above schema, the annotations @model & @searchable will create the datasources & all of the resources automatically for us.

There is also a @connection annotation that allows you to specify relationships between @model object types & an @auth annotation that allows you to specify authorization schemes within your GraphQL API.

Let’s look at how to create a new AWS Appsync API using the Amplify CLI with the Amplify GraphQL Transform library & connect it to a client-side React application.


1. Install & configure the CLI

First, we’ll install the AWS Amplify CLI:
npm i -g @aws-amplify/cli

With the AWS Amplify CLI installed, we now need to configure it with an IAM User:
amplify configure
For a video walkthrough of how to configure the AWS Amplify CLI, click here.



2. Connect the API to a client app

Next, we’ll create a new React app & change into the new directory:
npx create-react-app blog-app
cd blog-app

Now we’ll need to install the AWS Amplify client libraries:
yarn add aws-amplify aws-amplify-react
# or
npm install --save aws-amplify aws-amplify-react



3. Initialize the AWS Amplify project

From within the root directory or the newly created React app, let’s initialize a new AWS Amplify project:
amplify init
When asked if you’d like to use an AWS profile, choose Yes, using the profile we created when we configured the project earlier.

Once the project has been initialized, we’ll add the GraphQL API feature to our Amplify project:
amplify add api

This will walk us through the following steps to create the AWS AppSync GraphQL API:
  • Please select from one of the below mentioned services: GraphQL
  • Provide API name: blogapp
  • Choose an authorization type for the API: API_KEY
  • Do you have an annotated GraphQL schema?: N
  • Do you want a guided schema creation? Y
  • What best describes your project: One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)
  • Do you want to edit the schema now? Y

This will open a pre-populated Schema in your editor of choice & also give you the local file path of the new schema that was created.
Let’s take a look at the Schema. We’ll also make a small update by adding the content field to the Post type. Once you’ve updated the Schema, go ahead and save the file:
type Blog @model { id: ID! name: String! posts: [Post] @connection(name: "BlogPosts") } type Post @model { id: ID! title: String! content: String! blog: Blog @connection(name: "BlogPosts") comments: [Comment] @connection(name: "PostComments") } type Comment @model { id: ID! content: String post: Post @connection(name: "PostComments") }

In the above schema, we see that the Post & Blog types have the @model annotation. Object types that are annotated with @model are top-level entities in the generated API. When pushed, they will create DynamoDB tables as well as additional Schema & resolvers to hook everything together.
To learn more about the @model annotation, click here.

We also see the @connection annotation used in the types. The @connection annotation enables you to specify relationships between @model object types. Currently, @connection supports one-to-one, one-to-many, and many-to-one relationships. An error is thrown if you try to configure a many-to-many relationship.
To learn more about the @connection type, click here.

With the schema ready to go, we can now push everything to execute the creation of the resources:
amplify push

Once the resources are created, we’re ready to create the app & begin interacting with the API.

We can also now view the API in the AWS AppSync dashboard by clicking on the new API name.

From the AWS AppSync dashboard we can also begin executing queries & mutations by clicking on Queries in the left menu:

Let’s try to create a new blog with posts & comments & then query for the blog data.

In the AWS AppSync dashboard, click on Queries.
First, we’ll create a new blog:
mutation createBlog { createBlog(input: { name: "My Programming Blog" }) { id name } }

Next, we’ll create a new post in this blog (replace the postBlogId with the id returned from the above mutation):
mutation createPost { createPost(input: { title: "Hello World from my programming blog" content: "Welcome to my blog!" postBlogId: "bcb298e6-62ec-4614-9ab7-773fd811948e" }) { id title } }

Now, let’s create a comment for this post (replace commentPostId with the ID returned from the above mutation):
mutation createComment { createComment(input: { content: "This post is terrible" commentPostId: "ce335dce-2c91-4fed-a953-9ca132f129cf" }) { id } }

Finally, we can query the blog to see all articles & comments (replace the ID with the id of your blog):
query getBlog { getBlog(id: "bcb298e6-62ec-4614-9ab7-773fd811948e") { name posts { items { comments { items { content } } title id content blog { name } } } } }

4. Connect to the API from React

To connect to the new API, we first need to configure our React project with our Amplify project credentials. You will notice a new file called aws-exports.js located in the src directory. This file holds all of the information our local project needs to know about our cloud resources.

To configure the project, open src/index.js & add the following below the last import:
import Amplify from '@aws-amplify/core' import config from './aws-exports' Amplify.configure(config)

Now, we can begin performing mutations, queries & searches against the API.
The definitions for the GraphQL mutations that we will be executing will look like the this:
// Create a new blog const CreateBlog = `mutation($name: String!) { createBlog(input: { name: $name }) { id } }`
// Create a post and associate it with the blog via the "postBlogId" input field const CreatePost = `mutation($blogId:ID!, $title: String!, $content: String!) { createPost(input:{ title: $title, postBlogId: $blogId, content: $content }) { id } }`
// Create a comment and associate it with the post via the "commentPostId" input field const CommentOnPost = `mutation($commentPostId: ID!, $content: String) { createComment(input:{ commentPostId: $commentPostId, content: $content }) { id } }`

The definition for the GraphQL query that we will be executing will look like this:
// Get a blog, its posts, and its posts comments const GetBlog = `query($blogId:ID!) { getBlog(id:$blogId) { id name posts { items { id title content comments { items { id content } } } } } }`

5. Configure the client application

The first thing to do is configure Amplify with your web application. In the root of your app (in React this will be src/index.js), below the last import, add the following code:
import Amplify from 'aws-amplify' import config from './aws-exports' Amplify.configure(config)

Now, we can begin executing operations agains the API.


6. Perform mutations from the client

Creating a new blog:
// import the API & graphqlOperation helpers as well as the mutation import { API, graphqlOperation } from 'aws-amplify' import { CreateBlog } from './your-graphql-definition-location'
// next, we create a function to interact with the API state = { blogName: '' } createBlog = async () => { const blog = { name: this.state.blogName } await API.graphql(graphqlOperation(CreateBlog, blog)) console.log('blog successfully created') }

Creating a post for a blog:
// import the API & graphqlOperation helpers as well as the mutation import { API, graphqlOperation } from 'aws-amplify' import { CreatePost } from './your-graphql-definition-location'
// next, we create a function to interact with the API state = { postTitle: '' , postContent: '' } createBlog = async () => { const post = { title: this.state.postTitle, content: this.state.postContent, postBlogId: this.props.blogId // Or where your blogId data lives } await API.graphql(graphqlOperation(CreatePost, post)) console.log('post successfully created') }

Commenting on a post:
// import the API & graphqlOperation helpers as well as the mutation import { API, graphqlOperation } from 'aws-amplify' import { CommentOnPost } from './your-graphql-definition-location'
// next, we create a function to interact with the API state = { content: '' } createBlog = async () => { const comment = { content: this.state.content, commentPostId: this.props.commentPostId // Or where your commentPostId data lives } await API.graphql(graphqlOperation(CommentOnPost, comment)) console.log('comment successfully created') }



7. Perform queries from the client

Listing blog with posts & post comments:
// import the API & graphqlOperation helpers as well as the query import { API, graphqlOperation } from 'aws-amplify' import { GetBlog } from './your-graphql-definition-location'
// next, we create a function to interact with the API getBlog = async () => { const data = await API.graphql(graphqlOperation(GetBlog, { id: this.props.blogId })) console.log('blog successfully fetched', data) }


8. Modify the schema

If at any time you would like to modify the schema to add, update or delete anything, you can open the file where the schema is located, make your edits, & then run amplify push to update your AWS AppSync API.

. . .

Video Walkthrough In this video walkthrough, we create an AWS AppSync GraphQL API using the Amplify CLI & connect it to a React application.

Never miss a post from Chris Gregori, when you sign up for Ednsquare.