Getting started with Vue & GraphQL using . AWS AppSync To view the final project or to keep it as a reference, check out repo. this This project will be using the and packages. vue-apollo aws-appsync I am not a Vue developer. I’ve tried it when I’ve had the time to be learning something new, and I’ve really loved it so far, but really I specialize in React & React Native. I was looking for some documentation about how to get up and running with AppSync & Vue & I realized there was none, so I decided to write a blog post to show others how it’s done! If you haven’t already used it, is a service that allows you to quickly configure and deploy scalable serverless GraphQL APIs that also have features such as subscriptions (real time data) & multiple data sources among other things. AppSync In this post, we’ll walk through wiring up a new AppSync API, attaching it to, and using it in a Vue application. The application we will be building will need to demonstrate basic create, read, update, and delete operations. Creating the API The AppSync API will need to have the ability to create, read, update, and delete a list of items. To create a new API, go to the AWS AppSync dashboard and create a new API.Give the API the following schema: type Task {id: ID!name: String!completed: Boolean!} type Query {fetchTask(id: ID): Task} Click save, then click create resources. Once you’ve created your resources around the above schema, download your AWS AppSync.json file, we will need it to configure the client. You can download it by scrolling to the bottom of the main page in your API and clicking on next to Download “2. Download the AWS AppSync.js config file”: Save this file, we will need it once we have created our Vue app. Creating the client Next, we will use the Vue cli to create a new application using the vue router: vue init webpack vue-graphql Here are the exact options I chose: Next, we need to change into the directory and install the dependencies we will need: yarn add aws-appsync vue-apollo graphql-tag Now, move the AppSync.js file you downloaded from the AppSync dashboard, and save it in the src directory of your project. Next, we need to initialize the AppSync client. In , update the entrypoint to the following: src/main.js // main.jsimport Vue from 'vue'import App from './App'import router from './router' import AWSAppSyncClient from "aws-appsync"import VueApollo from 'vue-apollo'import appSyncConfig from './AppSync' const client = new AWSAppSyncClient({url: appSyncConfig.graphqlEndpoint,region: appSyncConfig.region,auth: {type: appSyncConfig.authenticationType,apiKey: appSyncConfig.apiKey,}},{defaultOptions: {watchQuery: {fetchPolicy: 'cache-and-network',}}}) const appsyncProvider = new VueApollo({defaultClient: client}) Vue.config.productionTip = falseVue.use(VueApollo) new Vue({el: '#app',router,components: { App },provide: appsyncProvider.provide(),template: '<App/>'}) Finally, we need to change our App.vue recognize that we do not want to render until the client has been rehydrated from local storage. Because the AppSync client stores our data locally, making it available offline, we need to be sure the data is available to the application when it loads. To do this, we can wait for a promise called , waiting for it to be fulfilled, before rendering our app. We provide a statement that will show and hide the main entrypoint of our app depending on if the client is hydrated: apollo.provider.defaultClient.hydrated v-if // App.js<template><div id="app" v-if="hydrated"><router-view/></div></template> <script>export default {name: 'App',data: () => ({ hydrated: false }),async mounted() {await this.$apollo.provider.defaultClient.hydrated();this.hydrated = true;}}</script> Once this is set up, run and you should be ready to move to the next step! npm run dev Creating queries & mutations Now that we have the base app up and running and our GraphQL backend ready to go, the next logical step may be to go ahead and begin writing the GraphQL queries that will correlate with our AppSync schema. In the src directory, let’s go ahead and create a mutations and queries folder: cd srcmkdir queries mutations Next, let’s go ahead and create the following queries: ListTasks.js // queries/ListTasks.js import gql from 'graphql-tag'export default gql`query listTasks {listTasks {items {idnamecompleted}}}` And the following mutations: AddTask.js UpdateTask.js DeleteTask.js // mutations/AddTask.js import gql from 'graphql-tag'export default gql`mutation addTask($name: String!, $completed: Boolean!) {createTask(input: {name: $name, completed: $completed}) {idnamecompleted}}` // mutations/UpdateTask.js import gql from 'graphql-tag' export default gql`mutation updateTask($id: ID!, $name: String!, $completed: Boolean!) {updateTask(input: {id: $idname: $namecompleted: $completed}) {idnamecompleted}}` // mutations/DeleteTask.js import gql from 'graphql-tag' export default gql`mutation deleteTask($id: ID!) {deleteTask(input: {id: $id}) {id}}` Now, go ahead and create a new file in the components folder called . Tasks.vue Finally, we will update the router to use the new Tasks.vue file as the entrypoint. Update to the following: index.js import Vue from 'vue'import Router from 'vue-router'import Tasks from '@/components/Tasks' Vue.use(Router)export default new Router({routes: [{path: '/',name: 'Tasks',component: Tasks}]}) Now that we have our application configured with AppSync, our queries and mutations created, and our folder structure configured, the only thing we need to do is create our Task component and wire everything together. There will be a lot going on in the component, and if you understand how Vue works, then the Template will make a lot of sense. If you are new to Vue, it is actually extremely straight forward for newcomers, as this is the first Vue app I’ve ever created and the first time I’ve ever used Vue! Tasks.vue is the final component. (also embedded below) Here Tasks.vue We will be breaking apart the functionality in this component and going into each area to describe what is going on. Template <template><div class="tasks"><h1>Task Manager</h1><input v-model="taskname" placeholder="Task Name" class="input"><button@click="createTask()"class="taskButton">Create Task</button><ul><liclass="task"v-for="(task, index) in tasks" :key="index"><p class="text">{{ task.name }}</p><p@click="toggleComplete(task)"class="text button">{{ task.completed ? 'completed' : 'not completed' }}</p><p@click="deleteTask(task)"class="text button delete">Delete task</p></li></ul></div></template> Our template is pretty basic. We are looping through an array of tasks, showing the name, whether the task is completed or not, and a delete button. We also have a text input with a button that will submit to the API to create a new task. Imports At the top of our script declaration, we import the queries & mutations that we will be needing to interact with our AppSync API. import ListTasks from '../queries/ListTasks'import CreateTask from '../mutations/CreateTask'import DeleteTask from '../mutations/DeleteTask'import UpdateTask from '../mutations/UpdateTask' Initial state Let’s now take a look at our initial data: data () {return {taskname: '',tasks: []}} We set an initial value of to an empty array, and to an empty string. will hold the task list array after it is fetched from AppSync, and will hold the value of our text input. tasks taskname tasks taskname Apollo configuration Next, we will look at our apollo configuration for the tasks array: apollo: {tasks: {query: () => ListTasks,update: data => return data.listTasks.items}} We have set an initial query of , and an function that returns just the array of items from the data and sets it as the value for tasks. ListTasks update CreateTask mutation Now, let’s see how we can perform a mutation to add a new task to our API: createTask() {const taskname = this.tasknameif ((taskname) === '') {alert('please create a task')return}this.taskname = ''const task = {name: taskname,completed: false} this.$apollo.mutate({mutation: CreateTask,variables: task,update: (store, { data: { createTask } }) => {const data = store.readQuery({ query: ListTasks })data.listTasks.items.push(createTask)store.writeQuery({ query: ListTasks, data })},optimisticResponse: {__typename: 'Mutation',createTask: {__typename: 'Task',...task}},}).then(data => console.log(data)).catch(error => console.error("error!!!: ", error)) We take the and create a new object called , setting completed to false. We then call , setting the variables as the task object we just created. taskName task $this.apollo.mutate We also supply both an & function to implement a snappy optimistic UI. This will basically assume the API call was successful and update our cache and UI, and if not it will then revert back to the state before the mutation was called. optimisticResponse update DeleteTask mutation deleteTask(task) {this.$apollo.mutate({mutation: DeleteTask,variables: {id: task.id},update: (store, { data: { deleteTask } }) => {const data = store.readQuery({ query: ListTasks })data.listTasks.items = data.listTasks.items.filter(task => task.id !== deleteTask.id)store.writeQuery({ query: ListTasks, data })},optimisticResponse: {__typename: 'Mutation',deleteTask: {__typename: 'Task',...task}},}).then(data => console.log(data)).catch(error => console.error(error))} This is very similar to the CreateTask mutation in the sense that we are not only updating our API, but also providing an optimistic response as well as update function for optimistic UI. UpdateTask mutation toggleComplete(task) {const updatedTask = {...task,completed: !task.completed}this.$apollo.mutate({mutation: UpdateTask,variables: updatedTask,update: (store, { data: { updateTask } }) => {const data = store.readQuery({ query: ListTasks })const index = data.listTasks.items.findIndex(item => item.id === updateTask.id)data.listTasks.items[index] = updateTaskstore.writeQuery({ query: ListTasks, data })},optimisticResponse: {__typename: 'Mutation',updateTask: {__typename: 'Task',...updatedTask}},}).then(data => console.log(data)).catch(error => console.error(error))} We use the mutation to toggle whether or not the task was completed. To do that, we take in the task as an argument, toggle the completed value to its opposite, then resubmit the task object to our API. UpdateTask The final Tasks.vue should look like the following: Conclusion To view the final project, go . here With this being my first time to use Vue, I was very surprised to see how easy it was to get up and running with everything. The API for Vue is very intuitive and I did not run into anything that wasn’t just a search away either on Google or within their documentation. I think for Vue developers looking to get up and running with GraphQL, this is a powerful and easy way to do so without having to deal with creating and maintaining your own backend & API. My Name is . I am a Developer Advocate at working with projects like and , and the founder of . Nader Dabit AWS Mobile AppSync Amplify React Native Training If you like React and React Native, check out out our podcast — on . React Native Radio Devchat.tv Also, check out my book, now available from Manning Publications. React Native in Action If you enjoyed this article, please recommend and share it! Thanks for your time.