WebSockets enable real-time, bidirectional communication between clients and servers, making them perfect for chat applications, live updates, and collaborative tools. Unlike traditional HTTP requests that follow a request-response pattern, WebSockets maintain persistent connections that allow both client and server to send messages at any time.
The key challenge in WebSocket applications is connection management - tracking active connections, organizing them into groups (like chat rooms), and handling disconnections gracefully. When building multi-room chat systems, you need to maintain data structures that map rooms to their active connections, broadcast messages only to relevant users, and clean up resources when users leave.
Broadcasting is the core pattern for real-time communication. When one user sends a message, the server must deliver it to all other users in the same room. This requires iterating through stored connections and sending the message to each WebSocket. Error handling is crucial here - if a connection has been closed unexpectedly, attempting to send will fail and you need to remove that connection from your tracking system.
Connection lifecycle management involves three phases: joining (accepting the connection and adding to room), active communication (receiving and broadcasting messages), and leaving (cleaning up on disconnect). The disconnect phase is particularly important because it can happen suddenly when users close browsers or lose network connectivity.
FastAPI's WebSocket support makes this straightforward with await websocket.accept() for connections, await websocket.receive_text() for incoming messages, and await websocket.send_text() for outgoing messages. The WebSocketDisconnect exception handles cleanup when connections end unexpectedly.
1from fastapi import FastAPI, WebSocket, WebSocketDisconnect
2from typing import Dict, List
3
4app = FastAPI()
5connections: Dict[str, List[WebSocket]] = {}
6
7@app.websocket("/ws/{room}")
8async def websocket_endpoint(websocket: WebSocket, room: str):
9 await websocket.accept()
10
11 # Add to room
12 if room not in connections:
13 connections[room] = []
14 connections[room].append(websocket)
15
16 try:
17 while True:
18 message = await websocket.receive_text()
19 # Broadcast to all in room
20 for ws in connections[room]:
21 await ws.send_text(f"Room {room}: {message}")
22 except WebSocketDisconnect:
23 # Clean up on disconnect
24 connections[room].remove(websocket)
25 if not connections[room]:
26 del connections[room]