Table of Contents
- Introduction to Real-time Communication
- What are WebSockets?
- HTTP vs WebSocket: Key Differences
- How WebSockets Work
- Introduction to FastAPI and WebSocket Support
- Setting Up FastAPI with WebSockets
- Example: Basic WebSocket Echo Server
- Broadcasting Messages to Multiple Clients
- WebSocket Clients (JavaScript Frontend Example)
- Best Practices for WebSocket Applications
- Conclusion
Introduction to Real-time Communication
In traditional web applications, communication is request-response based. The client sends a request and the server responds, and that’s the end of that communication cycle. However, real-time applications like chat apps, live notifications, collaborative editing tools, and online gaming require continuous, two-way communication between client and server.
Technologies like WebSockets make this possible by maintaining a persistent connection for real-time, bidirectional communication.
What are WebSockets?
WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. In simpler terms, WebSocket allows both the client and server to send data to each other at any time, without the client having to initiate every message.
The WebSocket protocol was standardized in 2011 and is supported by all major browsers.
HTTP vs WebSocket: Key Differences
Feature | HTTP | WebSocket |
---|---|---|
Communication | Request-response | Full-duplex |
Connection Lifespan | Short-lived (per request) | Long-lived (persistent) |
Overhead | High (headers sent with every request) | Low (single handshake) |
Use Case | Traditional websites, APIs | Real-time apps (chat, games) |
How WebSockets Work
- Handshake: WebSocket starts with an HTTP request using
Upgrade: websocket
header. - Persistent Connection: After the handshake, the TCP connection remains open.
- Bidirectional Data Flow: Server and client can send messages independently of each other.
The handshake looks like this:
Client: GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Server: HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Introduction to FastAPI and WebSocket Support
FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+ based on standard Python type hints. It has built-in support for WebSockets, making it an excellent choice for developing real-time applications.
FastAPI uses the websockets
library under the hood and provides an easy interface to accept WebSocket connections and interact with them.
Setting Up FastAPI with WebSockets
First, install FastAPI and an ASGI server like uvicorn:
pip install fastapi uvicorn
Project structure:
websocket_app/
├── main.py
Example: Basic WebSocket Echo Server
Let’s create a simple WebSocket server that echoes back any message the client sends.
main.py
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse
app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Echo</title>
</head>
<body>
<h1>WebSocket Echo Test</h1>
<input id="messageText" type="text" />
<button onclick="sendMessage()">Send</button>
<ul id='messages'></ul>
<script>
var ws = new WebSocket("ws://localhost:8000/ws");
ws.onmessage = function(event) {
var messages = document.getElementById('messages');
var message = document.createElement('li');
message.innerText = event.data;
messages.appendChild(message);
};
function sendMessage() {
var input = document.getElementById("messageText");
ws.send(input.value);
input.value = '';
}
</script>
</body>
</html>
"""
@app.get("/")
async def get():
return HTMLResponse(html)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
Now, run your server:
uvicorn main:app --reload
- Visit
http://localhost:8000/
- Type a message and send it
- You will receive the same message echoed back
Broadcasting Messages to Multiple Clients
To handle multiple clients and broadcast a message to all of them:
from fastapi import WebSocketDisconnect
clients = []
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
clients.append(websocket)
try:
while True:
data = await websocket.receive_text()
for client in clients:
await client.send_text(f"Broadcast: {data}")
except WebSocketDisconnect:
clients.remove(websocket)
- Whenever a client sends a message, it will be broadcasted to all connected clients.
- If a client disconnects, it is removed from the
clients
list to prevent errors.
WebSocket Clients (JavaScript Frontend Example)
You can connect to a FastAPI WebSocket server easily using plain JavaScript:
const socket = new WebSocket('ws://localhost:8000/ws');
socket.onopen = function(event) {
console.log("Connected to WebSocket server.");
};
socket.onmessage = function(event) {
console.log("Received: " + event.data);
};
socket.onclose = function(event) {
console.log("Disconnected from WebSocket server.");
};
socket.onerror = function(error) {
console.log("WebSocket Error: " + error);
};
// Sending a message
socket.send("Hello Server!");
Best Practices for WebSocket Applications
- Connection Management: Always handle client disconnections gracefully to avoid memory leaks.
- Authentication: Use authentication and authorization at WebSocket connection level if your app needs secure communications.
- Heartbeat / Ping-Pong: Implement periodic ping messages to ensure the client-server connection is alive.
- Scalability: Use tools like Redis Pub/Sub if you are scaling WebSocket servers horizontally.
- Error Handling: Always catch WebSocket exceptions (
WebSocketDisconnect
) and log or notify accordingly. - Security: Validate all incoming data and consider setting rate limits.
Example heartbeat implementation:
import asyncio
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
await websocket.send_text("ping")
await asyncio.sleep(10) # send a ping every 10 seconds
except WebSocketDisconnect:
pass
Conclusion
WebSockets open the door for creating powerful real-time applications with continuous, low-latency communication between clients and servers.
FastAPI makes it extremely easy to build WebSocket endpoints and handle real-time functionality like chat apps, notifications, collaborative editing, or live games.