Real-Time App with WebSocket through Django Channels

Source: https://medium.com/@wk_26361/the-history-and-usage-of-websockets-f865eff0d624

This article is written as a part of Individual Review of Fasilkom UI’s Software Engineering Project Course 2021

Real-Time Applications?

What’s Wrong with HTTP?

Don’t worry about that, HTTP is fine by itself. The only thing you need to know is that there is one thing that HTTP can’t do by itself, Real-Time Interactions. HTTP is a strictly unidirectional protocol. Which means, we are pulling data from server, or requests are initiated by the recipient, usually the Web browser (the server is passive).

HTTP-based Requests and Responses.

Before WebSocket, real-time applications can be built with HTTP by doing long polling.

I’ll give an example to explain what Long Polling is. Imagine there are one client and one server. The process is same as the normal HTTP request. The client requests to the server. The difference is that the server doesn’t immediately reply to the client. It holds the requests until certain time or until the server gets what’s the client needs.

From this scenario, I think you’ve already know that the requests are being held by server. The server elects to hold a client’s connection open for as long as possible, responses are given only after data becomes available or a timeout threshold is reached. The drawback is that the resources are tied-up by certain clients.

WebSocket

WebSocket connection

To interact with the server in real-time, the client requests HTTP upgrade connection to open the WebSocket connection with the Server. We can see that WebSocket connection is initially made from HTTP requests that upgrades the current connection.

[Client-side] Websocket Open Connection Handshake

Then, the server will accepts and upgrade the connection. Thus, handshake is made and then the two can communicate each other via WebSocket.

[Server-side] Websocket Open Connection Handshake

The server in WebSocket connection won’t only listen and gives responses to the client, but it can also send message to the client independently without any trigger from the client.

Django Channels

In order to upgrade our Django project with Channels, we need to install channels dependency first.

pip install channels

In this example, we’ll see simple chat application with Django Channels. I’ll walk the general idea to integrate our Django project with Channels, so you can know the big ideas and where to continue after reading this article.

First, we need to specify channels in our root of INSTALLED_APPS (so it can take control of runserver command).

Add channels into our INSTALLED_APPS.

Then, we need to modify our asgi.py to serve WebSocket connections.

Setup asgi.py for handling both HTTP and WebSocket connections.

As you see, WebSocket has its own routing pattern, that starts with ws:// or wss://. Now, let’s define our WebSocket endpoint patterns in our app:

Our WebSocket routing patterns.

With this pattern, our client can connect to our server through ws(s)://<host>/ws/chat/<room_name>/.

Now we’re done with the general configurations. Because we’re building a chat application, and don’t want to lose the chat history, we need to store it somewhere, the most used approach is to integrate Redis into our Channels. It is in the separate package, so we need to install it first.

pip install channel_redis
Specify our ASGI and Channel Layers.

You may be wondering, what are Channel Layers? Channel Layers allow you to talk between different instances of an application. To put it simply, we can think of them as group rooms that we’ve subscribed to. Imagine you’re sending messages to your friend in a Group Chat A. It won’t be delivered to Group Chat B, right? Only participants in Group Chat A can read the message. The same goes for Channel Layers, we can have many rooms to subscribe to.

Now that we have our Channel Layers ready, we can setup our Django’s WebSocket Consumer to connect with clients.

Our WebSocket consumer (part 1)

Because WebSocket is a full-duplex communication, there are handshakes on open and on close connection with the client. Because we’re building a chat application, on open connection, we will create a group chat with room_name given through URL, and delete it on disconnect.

What happens when one client send chat to other clients through WebSocket (implemented in chat_message function)? Our WebSocket consumer will listen to it and broadcast the message to other connected clients in the room (implemented in receive function).

Our WebSocket will broadcast messages to all connected clients.

Now, let’s implement the frontend’s side.

Frontend’s Side JS WebSocket.

Here we take the room name passed by user, then open WebSocket connection to our Django Channels. Our client-side will listen to messages that are sent by our Django through onmessage event.

Let’s take a look at the result. First, create a room.

Create room1
Two clients connected in the same room: room1.

We can see that messages from one client broadcasted by WebSocket to another.

ASGI over WSGI

WSGI (Web Server Gateway Interface) applications take a single request and return response at a time. This single and synchronous callable limits WSGI for long lived connections like WebSocket connections.

On the other side, ASGI (Asynchronous Server Gateway Interface) is a successor of the successful WSGI. ASGI’s goal is to continue become the standard compatibility between web servers, frameworks and applications like WSGI in asynchronous python. With ASGI, you can do most of the asynchronous jobs with Django (generally Python-based Web Server), since WebSockets are also performed asynchronously.

Implementation in Software Engineering Project Course 2021

With the same configurations as before, our team can upgrade the Django project with Channels. I’ll show you one of the example in our team’s Backend Project. It is to update our weekly income’s Chart when there are any new transactions approved by admin. The difference from previous configurations is that there are extra code to send this information when there are any new transactions approved.

When the transaction’s status changed to verified, we notify the admin through WebSocket.

Here, we get the channel_layer object then send through a group room named admin_dashboard, and send the message as JSON String.

Implementation Detail of notify_weekly_income()

Let’s see on the go!

Before verifying a transaction.
After verifying a transaction.

My Thoughts

I prefer to use WebSocket and have implemented it in our Project. WebSocket is very interesting because it can bring full-duplex messaging into Web Application Programming. You have to try it!

Thank you for reading, Happy Coding!

Currently studying at Faculty of Computer Science, Universitas Indonesia.