7 min readUpdated Oct 11, 2023

Ably Masterclass | Episode 1 - Building a realtime voting app in less than an hour

It was just a month ago that the idea of hosting a monthly masterclass series surfaced at Ably and yesterday I hosted the first episode where I taught the audience how they can build a realtime voting app in less than an hour.

So, in this post I'm summarising what happened, along with links to some useful resources to check out ?

I've hosted the slides online so you can check them out as well:

Slides from the presentation

As this was the first episode of the series I thought it'd be best to start off with an intro to what 'Realtime' means and demystify some buzzwords such as Pub/Sub, persistent connections, event-driven systems etc. I've explained this below:

A super brief intro to realtime concepts

Since the advent of the internet, its participating entities have communicated over the well-known Hypertext Transfer Protocol (HTTP). You have requests and responses and new connection cycles for each request-response style communication. This has worked incredibly well for applications where the primary goal is to fetch some data, send some data or get some computation done at the server-side.

But the past couple of years have seen data sharing move to a more event-driven approach. This means that the participating entities are interested in being notified of something as soon as it has occurred. This is the kind of communication that is popularly referred to as 'realtime'. Examples of such applications are live location-tracking apps, chat apps, hq-style quiz apps, live data streams involving bitcoin prices, stock markets, news, etc to name a few.

Some relatime use-cases as illustrated on the showcase page of Ably

If you think about such applications, the traditional HTTP based communication using REST requests falls short. Needing to set up new connection cycles each time, client-only initiated communications, and not to mention the data overload, leads to a lot of latency - and if there's one major thing to an application being 'realtime', it's that it is capable of communicating with the least possible latency. Right, so if not HTTP, then perhaps Long Polling? Well, Long Polling has almost the same disadvantages as HTTP based communication when it comes to realtime apps. Granted they can keep the connection open until the server has some data to return back in the response but we need something that can enable the server communicate with a client whenever it likes. In other words a server-initiated communication. So, Long Polling isn't an option either.

This is where the concept of 'Realtime subscriptions' comes into play. There are certain realtime protocols such as WebSockets, MQTT and SSE that allow for push-based communication (as opposed to the pull-based way of getting updates via HTTP). Let's take a quick look at WebSockets:

Communication starts off as an HTTP request but with an additional upgrade header. If the other party is compliant with WebSockets as well, the connection is upgraded leading to a full-duplex (communication is possible in both directions) and persistent (the connection can stay open for as long as you need) connection. This works perfectly for event-driven applications as any entity wanting to share and update simply pushes data to the other clients and they are instantly notified (latency is of the order of a few milliseconds).

This is how the concept of publishers and subscribers comes into play. Now that it's all a bit more clear, let's get into the app that I built during the webinar. Again, remember, I'm only doing a rapid summary of things I covered in the masterclass here. You should really be looking at the recording for detailed info on realtime concepts as well as the voting app.

Coding the voting app from scratch

So the end-result of the app I built looked something like so:

As you can see, these are two separate entities or apps, one a voting interface to cast votes using basic HTML buttons, and the other a chart that shows the resulting votes cast for different choices in the form of a chart. And oh did I mention? This chart updates in realtime as new votes get cast by users.

These two apps communicate in realtime via Ably, we use Fusioncharts to conveniently build a chart with our data and this whole app is publicly hosted using Glitch.

Starting with the voting interface app, it's a basic HTML layout, uses bootstrap to look fancy and has a few lines of code to connect to an Ably channel and publish votes as they are being cast. You should check out this directly on GitHub as a blog post is not a good place to host code. But again, just to sum up, the way you initialize Ably, attach to a channel and start publishing data is just a matter of a few lines of code:

        // Init Ably library
        var realtime = new Ably.Realtime({ key: '<YOUR-ABLY-API-KEY>' });
        // Attach to a channel
        var myVotingChannel = realtime.channels.get('voting-channel')
        // Publish data on the channel
        var castVote = function(choice){
            myVotingChannel.publish('vote', choice, (err)=>{
                console.log(err);
            });
        }

Now, on the chart app, it's also a basic HTML layout with a placeholder <div> tag to house the chart that'll appear as the data's coming through. The main things that need to be done in this app are:

  1. Init Ably
  2. Attach to the voting channel
  3. Subscribe to that channel
  4. Pass on the incoming data onto the chart
var realtime = new Ably.Realtime({key: '<YOUR-ABLY-API-KEY>'});
var myVotingChannel = realtime.channels.get('voting-channel');
myVotingChannel.subscribe('vote', (msg)=>{
    console.log(msg.data);
    // pass this onto the chart
    }

And for the chart itself, the main things that need to be done are:

  1. Prepare the data in an array of objects format
  2. Specify the metadata for the chart, like the type, dimensions, captions, axes, etc
  3. Init FusionCharts and render the chart with the below attributes

// Preparing the chart data
const chartData = []

// Chart Configuration
const chartConfig = {
    type: "pie2d",
    renderAt: 'chart-container',
    id: 'vote-chart',
    width: "100%",
    height: "400",
    dataFormat: "json",
    dataSource: {
        "chart": {
            "caption": "If age is only a state of mind",
            "subCaption": "Which category best describes YOUR state of mind right now?",
            "theme": "fusion",
        },
        // Chart Data from Step 2
        "data": chartData
    }
};

// Render the chart
FusionCharts.ready(function(){
    var fusioncharts = new FusionCharts(chartConfig);
    fusioncharts.render();
});

As mentioned, the code shown here is just a quick example, the full source code for the voting results app can be found in the GitHub repo.

One quick note is that FusionCharts doesn't quite take into consideration that data may change after the chart is rendered, so to enforce this, you'll need a special method they offer called setJSONData(). This basically requires you to specify the dataSource object in the chart config specified above.

FusionCharts.items['vote-chart'].setJSONData({
        "chart": {},
        "data": []
});

That's basically it!

Useful resources

  1. GitHub repo with full source code
  2. Presentation slides
  3. Recorded masterclass video
  4. Live demo of the voting interface app
  5. Live demo of the voting results app
  6. Ably Realtime docs
  7. FusionCharts docs

The next episode in the masterclass series

The next one is going to be about IoT, WebHooks, Zapier and other super fun things.

Join the Ably newsletter today

1000s of industry pioneers trust Ably for monthly insights on the realtime data economy.
Enter your email