DEV Community

gerard-sans for AWS

Posted on • Originally published at Medium

Create a cloud-enabled GraphQL API with AWS Amplify and Vue

Image for post

In this tutorial, we will learn how to build a GraphQL data-driven serverless app using Vue, AWS Amplify and AWS AppSync. We will create a new project with Vue, generate a serverless GraphQL API using AWS AppSync and build a client to consume it including real-time. We will cover:

  • Introduction to AWS AppSync
  • Setting up a new project with the Vue CLI
  • Creating a new GraphQL API and using your first GraphQL transform
  • Pushing your GraphQL API to the cloud
  • Building the client: adding queries, mutations and real-time
  • Publishing your app via the AWS Amplify Console
  • Cleaning up cloud services

In order to follow this post you will need a basic knowledge of GraphQL. You can learn the basics following this tutorial at graphql.org.

> Final solution and step by step tutorial in GitHub.

Please let me know if you have any questions or want to learn more at @gerardsans.

Introduction to AWS AppSync

AWS AppSync allows you to create highly scalable serverless GraphQL data-driven mobile and web apps by providing an open source Amplify Framework (consisting of AWS AppSync Clients, GraphQL transforms and the CLI), integrations with multiple data sources, and the AWS AppSync console.

  • GraphQL client: client-side library to securely access data from your GraphQL API. Built-in support for real-time and offline/delta client synchronisation.
  • Amplify CLI: set of commands, via theapi category, to automate the setup and provision of resources for AWS AppSync and Amazon API Gateway cloud services. Support for REST and GraphQL APIs.
  • GraphQL Transforms: custom GraphQL schema directives that can be used in your GraphQL schema to enable custom workflows.
  • Data sources: databases (Amazon DynamoDB for NoSQL, Amazon Aurora for RDBMS), searches (Amazon Elasticsearch Service), and AWS Lambda functions.

By using AWS AppSync, teams can quickly create highly scalable serverless GraphQL data-driven apps for mobile and web while leaving the heavy lifting to the Amplify CLI.

Image for post

AWS AppSync data-driven apps architecture overview

Setting up a new project with the Vue CLI

Before moving to the next section, please complete the steps described in “Build your first full-stack serverless app with Vue”.

Creating a new GraphQL API

For this post we are going to create a GraphQL API to list our favourite restaurants. To create it, we will use the following command:

amplify add api
Enter fullscreen mode Exit fullscreen mode

Answer the following questions

  • Please select from one of the below mentioned services GraphQL
  • Provide API name: RestaurantAPI
  • Choose the default authorization type for the API API key
  • Enter a description for the API key: (empty)
  • After how many days from now the API key should expire (1–365): 7
  • Do you want to configure advanced settings for the GraphQL API No, I am done.
  • Do you have an annotated GraphQL schema? No
  • Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
  • Do you want to edit the schema now? Yes

When prompted, replace the default schema with the following:

type Restaurant @model {  
  id: ID!  
  name: String!  
  description: String!  
  city: String!  
}
Enter fullscreen mode Exit fullscreen mode

You should be familiar with everything in the GraphQL schema above but for the @model directive. This is a GraphQL transform provided by AppSync.

Using your first GraphQL transform

GraphQL transforms allow AppSync to provide further customisation and support for common scenarios, so you don’t have to.

By adding@model to theRestauranttype we are telling the Amplify CLI runtime to create the resolvers to support queries, mutations and subscriptions in DynamoDB. Besides the regular CRUD operations, we are also getting some more advanced features like pagination and filtering that we are going to cover later.

Once we apply@model to a type we get access to these other transforms:

  • @key to configure custom index structures in DynamoDB
  • @searchable to enable searches using Amazon Elasticsearch Service
  • @connection to add relationships between types
  • @lambda to generate AWS Lambda resolvers
  • @auth to add fine grained multi-authorisation support
  • @versioned to add conflict resolution for offline scenarios

Learn how to use each transform in detail from the official docs.

GraphQL Transforms are implemented using custom GraphQL schema directives as defined in the GraphQL specification.

Pushing your GraphQL API to the cloud

Let’s run the push command to create the GraphQL API and see the results of using the @model transform:

amplify push
Enter fullscreen mode Exit fullscreen mode
  • Are you sure you want to continue? Yes
  • Do you want to generate code for your newly created GraphQL API Yes
  • Choose the code generation language target javascript
  • Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
  • Do you want to generate/update all possible GraphQL operations — queries, mutations and subscriptions Yes
  • Enter maximum statement depth [increase from default if your schema is deeply nested] 2

Write down your GraphQL endpoint and API KEY.

Run the command below to access the AWS AppSync console.

amplify console api
Enter fullscreen mode Exit fullscreen mode
  • Please select from one of the below mentioned services GraphQL

Testing your new GraphQL API

Once in the AWS AppSync console, click on Queries on the left side. This will open an editor that we can use to edit and test GraphQL queries.

Execute the following mutation to create a new restaurant:

mutation createRestaurant {  
  createRestaurant(input: {  
    name: "Nobu"  
    description: "Great Sushi"  
    city: "New York"  
  }) {  
    id name description city  
  }  
}
Enter fullscreen mode Exit fullscreen mode

Now, run this query to list the restaurant we just added:

query listRestaurants {  
  listRestaurants {  
    items {  
      id  
      name  
      description  
      city  
    }  
  }  
}
Enter fullscreen mode Exit fullscreen mode

Besides creating all common CRUD operations for your types, AWS AppSync also creates extra utility features like filters. Run this query to try using filters:

query searchRestaurants {  
  listRestaurants(filter: {  
    city: {  
      contains: "New York"  
    }  
  }) {  
    items {  
      id  
      name  
      description  
      city  
    }  
  }  
}
Enter fullscreen mode Exit fullscreen mode

AWS AppSync creates filters on GraphQL scalar types (ID, String, Int, Float, Boolean) for list operations like listRestaurants.

Querying data with queries

In the earlier sections, we made sure we had a working GraphQL API. On the client, we will start by displaying a list.

<template>  
  <div v-for="restaurant of restaurants" :key="restaurant.id">  
    {{restaurant.name}}  
  </div>  
</template>  
<script>  
import { API, graphqlOperation } from 'aws-amplify';  
import { listRestaurants } from './graphql/queries';  

export default {  
  name: 'app',  
  data() {  
    return {  
      restaurants: [],  
    }  
  },  
  created() {  
    this.getData();  
  },  
  methods: {  
    async getData() {  
      try {  
        const response = await API.graphql(graphqlOperation(listRestaurants));  
        this.restaurants = response.data.listRestaurants.items;  
      }  
      catch (error) {  
        console.log('Error loading restaurants...', error);  
      }  
    },  
  }  
}  
</script>
Enter fullscreen mode Exit fullscreen mode

From the code above, we are using API.graphqlto run the listRestaurantsquery within getData. Queries were created by the Amplify CLI during the push command. This call returns a promise that we handle by using async/await and render the result using v-for.

You might be wondering why we used listRestaurants.items. This is because AWS AppSync created an intermediate type ModelRestaurantConnection. This is so we can handle pagination scenarios together withlimit and nextTokenparameters.

listRestaurants(filter: ModelRestaurantFilterInput, limit: Int, nextToken: String): ModelRestaurantConnection 
type ModelRestaurantConnection {  
 items: [Restaurant]  
 nextToken: String  
}
Enter fullscreen mode Exit fullscreen mode

Creating data with mutations

In order to add new restaurants, we are going to create a data entry using form to take the required user input and pass it forward to the createRestaurant mutation.

<template>  
  <div>  
    <form v-on:submit.prevent>  
      <div>  
        <label>Name: </label>  
        <input v-model='form.name' class='input' />  
      </div>  
      ...  
      <button @click='createRestaurant' class='button'>Create</button>  
    </form>  
  </div>  
</template>  
<script>  
import { createRestaurant } from './graphql/mutations';  

export default {  
  name: 'app',  
  data() {  
    return {  
      form: { },  
    }  
  },  
  methods: {  
    async createRestaurant() {  
      const { name, description, city } = this.form  
      if (!name || !description || !city) return;  

      const restaurant = { name, description, city };  
      try {  
        const response = await API.graphql(graphqlOperation(createRestaurant, { input: restaurant }))  
        console.log('Item created!')  
        this.restaurants = [...this.restaurants, response.data.createRestaurant];  
        this.form = { name: '', description: '', city: '' };  
      } catch (error) {  
        console.log('Error creating restaurant...', error)  
      }  
    },  
  }  
}  
</script>
Enter fullscreen mode Exit fullscreen mode

Note how AWS AppSync instead of passing each field as an argument created an input type CreateRestaurantInput which makes our client code simpler and convenient.

type Mutation {  
 createRestaurant(input: CreateRestaurantInput!): Restaurant  
}input CreateRestaurantInput {  
 id: ID  
 name: String!  
 description: String!  
 city: String!  
}
Enter fullscreen mode Exit fullscreen mode

As we did before with queries, we are using async/await to run our mutation as we submit the form via onCreate. Once we get the result, we use the form data to update the list and clear the form inputs.

Adding real-time with subscriptions

To demonstrate real-time, we are going to use a subscription to update AppSync clients when new restaurants are added. AppSync clients will subscribe to listen for changes going through our GraphQL API. More specifically, restaurant creation mutations.

import { onCreateRestaurant } from './graphql/subscriptions';  

export default {  
  name: 'app',  
  created() {  
    //Subscribe to changes  
    API.graphql(graphqlOperation(onCreateRestaurant))  
    .subscribe((sourceData) => {  
      const newRestaurant = sourceData.value.data.onCreateRestaurant  
      if (newRestaurant) {  
        // skip our own mutations and duplicates  
        if (this.restaurants.some(r => r.id == newRestaurant.id)) return;  
        this.restaurants = [newRestaurant, ...this.restaurants];  
      }   
    });  
  },  
}
Enter fullscreen mode Exit fullscreen mode

We use createdto setup the subscription and immediately subscribe to start listening for notifications. Then for each notification, we will update our list of restaurants with changes.

Publishing your app via the AWS Amplify Console

The first thing you need to do is create a new repo for this project. Once you’ve created the repo, copy the URL for the project to the clipboard and initialise git in your local project:

git init  
git remote add origin [repo@repoofyourchoice.com](mailto:repo@repoofyourchoice.com):username/project-name.git  
git add .git commit -m 'initial commit'git push origin master
Enter fullscreen mode Exit fullscreen mode

Next visit the AWS Amplify Console in your AWS account. Click Get Started to create a new deployment. Next, authorise your repository provider as the repository service. Next, choose the new repository and branch for the project you just created and click Next. In the next screen, create a new role and use this role to allow the AWS Amplify Console to deploy these resources and click Next. Finally, click Save and Deploy to deploy your application!

Image for post

AWS Amplify Console deployment steps.

Cleaning up cloud services

If at any time, you would like to delete a service from your project and your AWS Account, you can do this by running:

amplify delete
Enter fullscreen mode Exit fullscreen mode

Conclusion

Congratulations! You successfully built your first GraphQL API using Vue and AWS AppSync. Thanks for following this tutorial.

If you prefer, you can follow the instructions in this video to build the same app but deploying to Amazon Cloudfront and Amazon S3.

Thanks for reading!

Have you got any questions regarding this tutorial or AWS Amplify? Feel free to reach out to me anytime at @gerardsans.

Image for post

My Name is Gerard Sans. I am a Developer Advocate at AWS Mobile working with AWS Amplify and AWS AppSync teams.
GraphQL is an open source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.

Top comments (0)