python 41 lines · 9 steps

Building a WebSocket chat with FastAPI

A connection manager tracks live WebSockets and fans out every message to all connected clients.

Explained by highlit
1from fastapi import FastAPI, WebSocket, WebSocketDisconnect
2 
3app = FastAPI()
4 
5 
6class ConnectionManager:
7 def __init__(self) -> None:
8 self.active: dict[WebSocket, str] = {}
9 
10 async def connect(self, websocket: WebSocket, username: str) -> None:
11 await websocket.accept()
12 self.active[websocket] = username
13 await self.broadcast(f"* {username} joined the chat")
14 
15 def disconnect(self, websocket: WebSocket) -> str:
16 return self.active.pop(websocket, "someone")
17 
18 async def broadcast(self, message: str) -> None:
19 stale = []
20 for connection in self.active:
21 try:
22 await connection.send_text(message)
23 except RuntimeError:
24 stale.append(connection)
25 for connection in stale:
26 self.active.pop(connection, None)
27 
28 
29manager = ConnectionManager()
30 
31 
32@app.websocket("/ws/{room}")
33async def chat_room(websocket: WebSocket, room: str, username: str = "anon") -> None:
34 await manager.connect(websocket, username)
35 try:
36 while True:
37 text = await websocket.receive_text()
38 await manager.broadcast(f"[{room}] {username}: {text}")
39 except WebSocketDisconnect:
40 left = manager.disconnect(websocket)
41 await manager.broadcast(f"* {left} left the chat")
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A central registry of active connections is the backbone of any broadcast-style real-time app.
  2. 2Broadcasting must tolerate dead sockets — collect failures and prune them instead of crashing the loop.
  3. 3The endpoint's job is just to accept, loop, and clean up; the manager owns all shared state.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a WebSocket chat with FastAPI — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code