Building Chat Applications

Chat applications are the classic WebSocket use case. Building one teaches you patterns that apply to many real-time systems — connection management, message routing, and state synchronization.

Basic Architecture

A simple chat system connects multiple clients through a central server:

Client A ──WebSocket──┐
                      │
Client B ──WebSocket──├── Server ── Message Store
                      │
Client C ──WebSocket──┘

When Client A sends a message, the server receives it, optionally stores it, and broadcasts it to other connected clients. The server maintains a list of active connections.

Managing Connections and Rooms

Most chat applications organize conversations into rooms or channels. The server tracks which connections belong to which rooms:

from typing import Dict, List
from fastapi import WebSocket

class ConnectionManager:
    def __init__(self):
        self.rooms: Dict[str, List[WebSocket]] = {}
    
    async def join_room(self, room: str, websocket: WebSocket):
        if room not in self.rooms:
            self.rooms[room] = []
        self.rooms[room].append(websocket)
    
    async def leave_room(self, room: str, websocket: WebSocket):
        if room in self.rooms:
            self.rooms[room].remove(websocket)
    
    async def broadcast_to_room(self, room: str, message: str):
        for connection in self.rooms.get(room, []):
            await connection.send_text(message)

When a user joins a room, add their connection to that room's list. When they send a message, broadcast it to everyone in the same room.

Essential Features

User presence shows who's online. Track connected users and broadcast join/leave events. Consider "last seen" timestamps for users who disconnect.

Typing indicators show when someone is composing a message. Send a "typing" event when the user starts typing, and clear it after a timeout or when they send the message.

Read receipts confirm message delivery. Track which messages each user has seen and sync this state across their devices.

Message history lets users see past conversations. Store messages in a database and load recent history when users join a room. Implement pagination for older messages.

Message Protocol

Define a clear message format for client-server communication:

{
    "type": "message",
    "room": "general",
    "content": "Hello everyone!",
    "timestamp": "2024-01-15T10:30:00Z"
}

Use a type field to distinguish message types — chat messages, typing indicators, presence updates, and system notifications can all flow through the same connection.

Handling Edge Cases

Users disconnect unexpectedly. Detect disconnections and clean up their presence state. Messages sent while disconnected should queue for delivery or show as failed. Consider offline message storage for important communications.

See More

You need to be signed in to leave a comment and join the discussion