I recently tackled a problem to implement real time communication feature in my web application. I'll be sharing how I did it in this article.
My Real Time Communication Challenge
Recently, I had to implement WebSockets in one of my personal projects, something I had never done before. This led me to Django Channels, a package for handling WebSockets in Django.
It was a good learning experience for me as I had to learn a bit of Javascript too. So after a bit of tutorials and research, I was ready to solve my problem.
Django-channels works by creating a consumer and routes in the backend, while Javascript is used in the frontend to open a websocket connection to the specified routes and keeps the connection open so data can be exchanged in real time between the backend and the frontend.
Setting up Django channels
Installing django-channels
pip install channels
Updating settings.py file
INSTALLED_APPS = [
...
'channels',
]
ASGI_APPLICATION = 'educa.asgi.application'
Creating the web consumer
A consumer handles the Websocket connections
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from django.utils import timezone
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.user = self.scope['user']
self.id = self.scope['url_route']['kwargs']['course_id']
self.room_group_name = f'chat_{self.id}'
# join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
# accept connection
await self.accept()
async def disconnect(self, close_code):
# leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# receive message from WebSocket
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
now = timezone.now()
# send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'user': self.user.username,
'datetime': now.isoformat(),
}
)
# receive message from room group
async def chat_message(self, event):
# send message to WebSocket
await self.send(text_data=json.dumps(event))
Setting up the routes
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/room/(?P<course_id>\d+)/$',
consumers.ChatConsumer.as_asgi()),
]
Configuring asgi.py file
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
import chat.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'educa.settings')
django_asgi_app = get_asgi_application()
application = ProtocolTypeRouter({
'http': django_asgi_app,
'websocket': AuthMiddlewareStack(
URLRouter(chat.routing.websocket_urlpatterns)
),
})
Frontend Websocket connection
Finally I wrote the javascript code to open the Websocket connection
const courseId = JSON.parse(
document.getElementById('course-id').textContent
);
const requestUser = JSON.parse(
document.getElementById('request-user').textContent
);
const url = 'wss://' + window.location.host +
'/ws/chat/room/' + courseId + '/';
const chatSocket = new WebSocket(url);
a
chatSocket.onmessage = function(event) {
const data = JSON.parse(event.data);
const chat = document.getElementById('chat');
const dateOptions = {hour: 'numeric', minute: 'numeric', hour12: true};
const datetime = new Date(data.datetime).toLocaleString('en', dateOptions);
const isMe = data.user === requestUser;
const source = isMe ? 'me' : 'other';
const name = isMe ? 'Me' : data.user;
chat.innerHTML += '<div class="message ' + source + '">' +
'<strong>' + name + '</strong> ' +
'<span class="date">' + datetime + '</span><br>' +
data.message + '</div>';
};
chatSocket.onclose = function(event) {
console.error('Chat socket closed unexpectedly');
};
const input = document.getElementById('chat-message-input');
const submitButton = document.getElementById('chat-message-submit');
submitButton.addEventListener('click', function(event) {
const message = input.value;
if(message) {
// send message in JSON format
chatSocket.send(JSON.stringify({'message': message}));
// clear input
input.value = '';
input.focus();
}
});
input.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
// cancel the default action, if needed
event.preventDefault();
// trigger click event on button
submitButton.click();
}
});
input.focus();
This project was a significant learning experience. Not only did I learn Django Channels, but I also got hands-on with JavaScript.
This is my first attempt at writing an article. I have always wanted to write articles, especially on technical topics relating to programming, but I haven't being able to bring myself to start.
Funny enough, a program I joined has actually pushed me to write this article and publish it. That program is the HNG Internship
What is HNG Internship
This internship is a fast paced boot camp for advanced learners to get in shape for job offers. It provides you with the opportunity to gain real-world experience by working on actual projects for eight weeks and also network with like minded individuals.
You can read more about HNG Internship here. You can also explore the HNG premium network which gives you the opportunity to get access to exclusive opportunities.
Why I joined HNG Internship
I joined the program so I could gain more confidence in applying for jobs seeing that throughout the 8 weeks, I will be working on real project, which is a much needed experience for me right now. I will be pushing myself to limits and boundaries I have never crossed in my programming journey during this program. I have been pushed to write this article so I can be promoted the next stage.
Thank you for reading. I hope to share more about my dev journey and experience during HNG Internship with you.
Top comments (1)
Thank you for this article!