Building a Real-time Game of Thrones Voting App with GraphQL and Chart.js
Tags: javascript, graphql, showdev, hasura
Published: 2019-05-06 07:34:34

---
title: Building a Real-time Game of Thrones Voting App with GraphQL and Chart.js
published: true
description: Building a full-fledged real-time GraphQL Application with Vue.js and Chart.js plus jumping onto the Game of Thrones hype train.
tags: javascript, graphql, showdev, hasura 
---
![Header](https://thepracticaldev.s3.amazonaws.com/i/nu2qvpox9osdbgseo8dh.png)
# TL;DR 🕑

{% twitter 1121848927395950592 %}

# The Long Version 😉

I've always wanted to do a voting app because hey - they're cool!
I read an [article](https://blog.hasura.io/graphql2chartjs-realtime-charts-made-easy-with-graphql-and-chartjs/) on how to build charts in JavaScript with [chart.js](https://www.chartjs.org/) and GraphQL using an amazing tool called [graphql2chartjs](https://github.com/hasura/graphql-engine/tree/master/community/tools/graphql2chartjs). The timing was amazing, Game of Thrones' battle of Winterfell was a few days away so I decided to get a taste of who folks thought would stray into the long night on the episode. 

I tweeted this out and waited ⏳

{% tweet 1121848218789322752 %}

The app got a very shocking **10,000** votes before the episode aired

![Votes Tally Image](https://thepracticaldev.s3.amazonaws.com/i/vrb6pvvt4l5m2d1gmoy1.png)

Not to mention, over 50% of the votes were for Grey Worm [#RIPGreyWorm](https://twitter.com/SabiqueAkhan/status/1123229462923890689)

![Grey Worm Votes](https://thepracticaldev.s3.amazonaws.com/i/56yq9tw9h13eola2ri9u.png)

Scary stuff! I reset the votes tally so you can get a feel of the app and its functionality.
## 🚀 [Give it a go! ](https://valar-viz.netlify.com/) 📈📈

# ⚙️ How I built it ⚙️

The App has: 
📊 [Vue.js](https://vuejs.org/) + [Chartjs](https://www.chartjs.org/) on the frontend 🖥️
😈 [Hasura](https://hasura.io/) + [Apollo GraphQL](https://www.apollographql.com/) in the backend ⚡
🚀 Deployed on [Netlify](https://www.netlify.com/) 🔥

# 🔧 Backend 🔧

I used Hasura and it's one-click [Heroku Deployment](https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html) to set up my backend. Hasura gives us real-time GraphQL over a PostgreSQL database. Next up we need to define a schema, in the **Data** section of the API Console, we have to create a `characters` table with the following columns...

-`id` holds an integer value, is the primary key and is auto incremented
-`name` holds a text value
-`votes` hold an integer value and have the default value set to 0

Once you have the schema setup, you have to enter the character names manually in the **Data** section of the API Console.

We're done with the backend for now.

# ✨ Frontend ✨
Like I said above, I did the frontend in Vue.js, we’d have to install it before we can go on and to do that we’ll need [Node.js](https://nodejs.org/en/) on our system. Once we’ve got node installed, enter the following command to install the vue cli `npm i -g @vue/cli`. To set up a new Vue project, we enter the following command `vue create myapp`, replace *myapp* with whatever funky name you want to call this app and click **default** when prompted to pick a preset. When done initializing, your folder structure should resemble the one below.

![](https://cdn-images-1.medium.com/max/1250/1*HYcFt4gXD23L0ujilE4YmQ.png)

When the app is done initializing, `cd <myapp>` and enter `npm run serve` to run your app. The command line will display a local address that your app is being hosted on, open your browser and go to that address. This should be what you see.

![](https://cdn-images-1.medium.com/max/2000/1*OVIt-0D3nJCcmahPc2dVKw.png)

# Putting it Together 🤝

At this point, we have a basic Vue App on the frontend and our backend with Hasura is initialized. The goal is to create an app to visualize the death votes for Game of Thrones characters, so we go on and install our visualization tool, chart.js with the following commands `npm install vue-chartjs chart.js --save`. We also install graphql2chartjs the tool that helps us read graphql data and use that in our charts, to do that we run the command `npm install --save graphql2chartjs`. 

We've got to import a few files into our **main.js** file. After which, your **main.js** should look like this:
{% gist https://gist.github.com/malgamves/46615e97f14090849f8dcfb7ba116960 %}

A lot of the packages imported are explained in two articles I did on queries and mutations in GraphQL below...

{% link https://dev.to/malgamves/vue-x-hasuragraphql-2pki %}
{% link https://dev.to/malgamves/using-mutations--22d2 %}

Seeing as the chart will be displaying data in real-time, we will be using [subscriptions](https://docs.hasura.io/1.0/graphql/manual/subscriptions/index.html) which we will cover now. As usual, there are a few things we have to look out for, on lines **16** and **20** you need to paste the name of your app so that Apollo can help your Vue app communicate with the GraphQL backend. 

Pay attention to line **19**, our implementation of subscriptions uses a web socket to keep a constant connection to the server and serve fresh and updated data to the UI. 

After tinkering around with the **main.js** file, in the **src**, we have to create a folder called **constants** where we create a file called **graphql.js**. In that file, we need to import `gql` by pasting `import gql from graphql-tag;` at the top of the file.

The **graphql.js** file lets us have a common file to keep all our queries, mutations and subscriptions. This makes it easy to export them into the **App.vue** when we need to. 

Your **graphql.js** file should look something like this...

{% gist https://gist.github.com/malgamves/eaac3553d7dec9b598e5b180a4798c3e %}

The `ALL_VOTES_QUERY` query gets the `name` and `id` of an entry in the characters table. Similarly, you can try out other operations and add them to the file as I have. Similarly, 

We then create the chart component that we will later export into our **App.vue** file. We call this **BarChart.js**. This is the standard format if one wants a reactive chart that gets data from an API which in our case is our GraphQL API. The vue-chart.js [docs](https://vue-chartjs.org/guide/#introduction) cover this in detail.

{% gist https://gist.github.com/malgamves/f390b53cf4449e159e6df414fbe37a84 %}

Now, in your **App.vue** file, the changes you make will be displayed when 
{% gist https://gist.github.com/malgamves/e9b671cc612210ad8dd061b0dd7cac5d %}

In the **App.vue** there are three snippets that you need to pay attention to:

#### Number 1️⃣  
```html 
<div v-for="charName of characters" v-bind:key="charName.id">
     <button class="button" @click="updateVotes(charName.id)">
        {{charName.name}} 
     </button>
</div>
```

The variable `characters` stores the result of the `ALL_CHAR_QUERY` query. We use the `v-for` directive to print out each item in the result array as the title of a button. It is important that we use the `v-bind` directive to bind the character ID and use it as a key to iterate over the items in the results array i.e all the characters in our database. This will prove useful when binding each vote to a specific character.

#### Number 2️⃣ 
```html 
<h2 v-if="loading">
⚖️ Total Votes: {{totalVotes.characters_aggregate.aggregate.sum.votes}}
</h2>
```

I wanted to be able to show the total number of votes places. This snippet does just that. The number updates as users vote in realtime, which mean we would have to subscribe to that data. To achieve this... I left the subscription to do this out of the **graphql.js** code I shared. Don't worry though, the Hasura Graphiql has a very intuitive way of creating subscriptions (*shown below*) by ticking boxes and it will write out the text for you. 

![API Console Gif](https://thepracticaldev.s3.amazonaws.com/i/i5u3xbl4ojhupkhzuv91.gif)

Once you do that, copy the subscription generated and paste it in the **graphql.js** file to enable it. 


We use `v-if` to display the data only if the data is done loading otherwise you can get an undefined object at times and we wouldn't want that, would we? 


#### Number 3️⃣
```html 
<div class="chart">      
      <bar-chart v-if="loaded" :chartData="chartData" :options="options" :width="200" :height="300"/>
</div>
```

Here, we import the `bar-chart` component we created with **BarChart.js** and pass the data using the `chartData` and `options` variables. Again you see us using the `v-for` directive to render the chart only after the data has loaded, we do this to avoid errors.

After these additions, you can style the application and `npm run serve` to see some pretty cool bar charts. That's pretty much how the web app came to be. It's worth mentioning that when building it in, I gave some thought to adding and omitting certain functionality. There are a few things I left out, namely:

- I didn't restrict voting to a single vote per user
- I didn't give users the ability to start their own poll

The project is up on [GitHub](https://github.com/malgamves/GameOfCharts), feel free to fork and add any functionality you need or would want!

{% github https://github.com/malgamves/GameOfCharts %}

Drop me a question on [Twitter](https://twitter.com/malgamves) if you have any. Hope you enjoyed reading this. Till next time :)