Building a Progressive Todo Web App with Vuetify, Vuex and GraphQL

TL;DR

Build a progressive todo app with Vuetify, Vuex, VueApollo and integrate GraphQL APIs using Hasura GraphQL Engine.

Instant setup. App Source Code 👉 vuetify-vuex-todo-graphql

Vuetify + Vuex + Hasura GraphQL

Tech Stack

This progressive web app uses the following frameworks/servers

  • Vue.js with Vuetify for Material Design UI, Vuex for state management, VueApollo for making GraphQL queries
  • Hasura GraphQL Engine to get instant GraphQL APIs over Postgres

Vuetify Framework

Vuetify is a semantic component framework for Vue. It is built according to Google's Material Design Spec and has intuitive properties without complex classes and markup.

In this app, we make use of Vuetify components like VGrid, VCard, VList, VTextField, VBtn among a bunch of available reusable components.

The progressive todo web app is a fork of davidgaroro/vuetify-todo-pwa  which uses

  • Vuetify for the TodoMVC UI with material design
  • Vuex for state management

Here's how the todo app looks like with Vuetify's material design components:

We added vue-apollo to this app and configured ApolloClient to make GraphQL queries for storing and managing the todos in the database. We will use Hasura to get instant GraphQL APIs.

Hasura + vue-apollo

Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.

We will integrate Hasura GraphQL APIs with this todo app. Refer the github link to deploy Hasura and create the todos table.

Once we have Hasura deployed, we can configure the frontend to make GraphQL queries. We add all modules required to configure ApolloClient.

npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag

Note: You can also use apollo-boost, if you don't need fine grained control over configuration

We define ApolloClient in src/apollo.js file in the todo app,

import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'

const httpLink = new HttpLink({
  // You should use an absolute URL here
  uri: 'https://myapp.herokuapp.com/v1alpha1/graphql'
})

// Create the apollo client
export const apolloClient = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
  connectToDevTools: true
})

const apolloProvider = new VueApollo({
  defaultClient: apolloClient
})

// Install the vue plugin
Vue.use(VueApollo)

export default apolloProvider

We need to just configure Hasura GraphQL Engine endpoint in the httpLink and import this apolloProvider in main.js and add it to the Vue instance like this:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import apolloProvider from './apollo'
import './registerServiceWorker'
import './vuetify'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  apolloProvider,
  render: h => h(App)
}).$mount('#app')

Once this is configured, the apolloClient can be imported and used across the app.

We define the GraphQL queries/mutations and trigger them in Vuex store.

For example, to fetch all the todos, we define a simple query to fetch todos sorted by latest id.

const todoQuery = gql`{
    todos(order_by: [{id: desc}]) {
      id
      text
      is_completed
    }
}`

and in our actions, we make this query using apolloClient and invoke the mutation handler using commit which will update the state.

const actions = {
  async fetchTodos ({ commit }) {
    const { data } = await apolloClient.query({query: todoQuery})
    commit('fetchTodos', data.todos)
  },
}

Note that we are making use of async, await which makes the syntax cleaner.

Let's define a GraphQL mutation to insert a new todo.

const todoMutation = gql`
  mutation insert_todos($text: String!) {
    insert_todos(objects: [{text: $text}]) {
      affected_rows
      returning {
        id
        text
        is_completed
      }
    }
}`

This mutation accepts a $text variable and inserts it into the todos table.

Similarly we define GraphQL mutations for adding/updating/deleting todos and we define actions to make the mutation and update the state in the Vuex store.

Progressive Web App

This todo app is a PWA and comes with boilerplate setup for

which can be configured to get a Lighthouse score of 100.

Todo App Source Code

I have put together the app with complete GraphQL integration so that you can get started quickly and extend it further!

Check it out on github.

Note that this app doesn't have any user authentication yet and its currently a demo to integrate GraphQL queries/mutations with Vuetify + Vuex with Hasura.

Take it for a spin and let us know what you think. If you have any questions or run into any trouble, feel free to reach out to us on twitter, github or on our discord server.


Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.


PS: We’re hiring!