Build Real-time Apps by Learning WebSockets
Tags: javascript, webdev, programming, realtime
Published: 2018-05-22 07:06:59

---
title: Build Real-time Apps by Learning WebSockets
published: true
description: Learn to write real-time apps by using WebSockets, leveling up your dev skills.
tags: javascript,webdev,programming,realtime
---

As a studying web developer, once you learn to query external APIs to display data in your UI, a whole new world opens up. 

When interviewing for UI developer positions at various companies, I would say something like, "just give me the endpoints and I'll handle the rest ;)".

All of their other questions like "How do you handle adversity?" or "How do you handle disputes with stakeholders?" become moot.

With HTTP requests, I can get data, I can post data, and I can delete data. I do it all - I am definitely a fit for your team whether you know it or not.

This sounds great in the echo chamber of my mind. I distinctly remember feeling like a champion developer because I knew how to send requests to REST APIs.

Then, they had me make a chat application.

# The Issue with Polling

If you're like me, you didn't understand how chat apps worked when you became a web developer. You might've thought, hey I'll just send a GET request every half-second or so to retrieve the recent chat messages.

In JavaScript, that might look a little something like this:

```javascript
let clearIntervalId
let messages = []

function pollChatMessages() {
  const clearIntervalId = setInterval(() => {
    messages = await axios.get('https://api.example.com/threads/1/messages') // totally fake url
  }, 500)
}
```

This is called polling, and it'll work for a little while. One of my clients couldn't tell the difference, so long as there were only a couple users.

This function would be executed on some interval inside a singleton that exists inside the scope of our web application. If we wanted to kill the polling we could call `clearInterval(clearIntervalId)`.

If we were chatting with 10 people, we would be running 10 polls from our browser. Likewise, those 10 people would also be running a poll for each person they were chatting with.

And what if some threads have hundreds of messages? That is a ton of needlessly large requests for a simple chat app.

The problem here is that the use of polling assumes that there is no way for a client like our browser to subscribe to a server. We can do better with a little networking.

# Networking Basics

Let's start with some networking basics, what is a **socket**?

A **TCP socket** is an _endpoint instance_ defined by the combination of an IP address with a port, in the context of either a listening state (a server) or a particular TCP connection (a client, like your browser).

A **TCP connection** is defined by the pairing of two sockets.

There are three main kinds of transports that we commonly use in browser web applications:

* **XMLHTTPRequests**, or just HTTP for short. Send a single request and get a single response. These are pretty common.
* **Server-Sent Events**, or SSE. Send a long-lived request and be able to stream data from the server. Great for real-time data streaming, particularly when the client doesn't need to send messages back to the server.
* **WebSockets**, the only transport that allows for bidirectional streaming of text and binary data. We'll dive a little further into it.

Here's a diagram I stole from [High-Performance Browser Networking](https://hpbn.co), which illustrates the communication flow between each of these transports. It's a good book to check out if you're serious about improving the performance of your web apps.

![ws](https://thepracticaldev.s3.amazonaws.com/i/47j90glrwxk8dv2perdp.png)

In most tutorials that deal with external data, you'll deal with the left-most paradigm's HTTP requests. Actually, all of these flows are initiated with an HTTP request, as shown by the blue arrows.

I don't commonly see articles or tutorials on SSE, but [MDN has a good reference](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) in case a one-way data stream sounds intriguing.

The third flow is most interesting to us - it gives us the ability to communicate with the server over a single long-lived connection.

# Enter WebSockets

As described by the [Mozilla Developer Docs](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API),

<blockquote>  
WebSockets are an advanced technology that makes it possible to open an interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
</blockquote>  

That's fantastic, we don't need to do any polling! But how does it work?

The lifecycle of a WebSocket connection between a client and server goes like this. Imagine our server is hosted at `https://api.example.com` on port 8080 and our client is someone's browser.

1. The client sends a GET request to `api.example.com:8080`, with a couple of headers that indicate it wants to establish a WebSocket connection with the server. One of these is called `Sec-WebSocket-Key`, and is used to secure the connection between the client and server. The server derives a response header from this key called `Sec-WebSocket-Accept`, which indicates that the server does indeed support WebSockets and that it doesn't try to process the request as an ordinary HTTP request.
2. The server responds with code 101 - Switching Protocols, indicating that the handshake is complete and the client/server can start exchanging messages [encrypted over XOR](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#Exchanging_Data_Frames). Sparing the details of this data masking, we can now publish and subscribe to text or binary messages over this connection.
3. At any point after a successful handshake either the client or server can send a ping in order to check whether the other party is still connected. If the recipient of the ping does not send back a pong, it may have been disconnected.

In JavaScript, we can connect to a WebSocket server like this:

```javascript
const thread = document.getElementById('chat-thread-1')

const conn = new WebSocket('ws://api.example.com/threads/1')

conn.onclose = function(event) {
  console.log('Connection closed')
}

conn.onmessage = function(event) {
  console.log('Message received.')
  const message = document.createElement('p')
  message.textContent = event.data
  thread.append(message)
}
```

We can invoke the built-in WebSocket constructor to create a connection, at which point we can set up the event handlers to decides what happens when a message is received.

We can also send messages, what if we had an `input` element that the client could enter text to chat with other users? That sure would be useful.

```javascript
function sendMessage() {
  const input = document.getElementById('chat-thread-1-input')
  conn.send(input.value)
  input.value = ''
}
```

Better yet, what if we wanted to communicate more complex data with a message type and a timestamp, perhaps in the form of JSON?

```javascript
function sendMessage() {
  const input = document.getElementById('chat-thread-1-input')

  const message = {
    type: 'message',
    text: input.value,
    date: Date.now(),
  }

  conn.send(JSON.stringify(message))
  input.value = ''
}
```

With a little DOM manipulation, we are not far from a somewhat real-world chat application. Chats are neat and all, but what else can we do with this technology?

# Other Applications of WebSockets

For this chat example, the application of WebSockets is obvious: send and receive text messages.

If you frequent [dev.to](https://dev.to) then you might've noticed that they have a contest going on, called [Build a Realtime App with Pusher](https://dev.to/devteam/first-ever-dev-contest-build-a-realtime-app-with-pusher-4nhp).

The Pusher API is built on the basis of WebSockets. Some of its use cases include:

* updating location in real-time, say for journies and deliveries
* real-time graphs
* collaboration over a browser, mobile, or IoT
* online gaming

Personally, I'm thinking of building a cloud markdown editor that'll help me with editing and sharing posts in a single place. I'd store my markdown content on a server and ideally be able to view/edit it from my Mac or my phone.

If I want to share a post with someone to edit, I'd drop them a link and I'd be able to see their cursor and notes in real-time, similar to how a Google doc works.

Of course, part of the fun for me is implementing the server myself. Whether I'd consume a service like Pusher will depend on my productivity/pain with the implementation.

If this intrigues you as well, you may find these links useful:

* [Writing WebSocket Servers](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers) on MDN
* [How to Build a Chat Application using React, Redux, Redux-Saga, and Web Sockets](https://medium.freecodecamp.org/how-to-build-a-chat-application-using-react-redux-redux-saga-and-web-sockets-47423e4bc21a)
* [Build a Realtime Chat Server With Go and WebSockets](https://scotch.io/bar-talk/build-a-realtime-chat-server-with-go-and-websockets)

Curious for more posts or witty remarks? Follow me on [Medium](https://medium.com/@iwilsonq), [Github](https://github.com/iwilsonq) and [Twitter](https://twitter.com/iwilsonq)!