WebSocket: Building a Real-Time Chat Application
Overview
In this chapter, we will build a real-time chat application using WebSockets. This application will allow multiple users to join a chat room, send messages, and receive messages in real-time. We will use FastAPI for the server and JavaScript for the client.
Setting Up the Server
We will start by setting up the server using FastAPI. The server will handle WebSocket connections, manage chat rooms, and broadcast messages to all connected clients.
Step 1: Install Dependencies
First, we need to install FastAPI and Uvicorn. Open a terminal and run the following command:
pip install fastapi uvicorn
Step 2: Create the Project Structure
Create a new directory for your project and navigate into it. Inside this directory, create a file named main.py
:
mkdir chat-app
cd chat-app
touch main.py
Step 3: Implement the WebSocket Server
Open main.py
and add the following code to create a WebSocket server that handles chat messages:
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from typing import List
app = FastAPI()
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
await manager.broadcast(data)
except WebSocketDisconnect:
manager.disconnect(websocket)
In this code:
- We create a
ConnectionManager
class to manage active WebSocket connections. - The
connect
method accepts a WebSocket connection and adds it to the list of active connections. - The
disconnect
method removes a WebSocket connection from the list of active connections. - The
broadcast
method sends a message to all active connections. - In the
websocket_endpoint
function, we handle incoming WebSocket connections, receive messages, and broadcast them to all connected clients.
Step 4: Run the Server
To run the server, use the following command:
uvicorn main:app --reload
This command tells Uvicorn to run the app
instance defined in the main
module. The --reload
flag enables auto-reloading, so the server restarts whenever you make changes to the code.
Creating the Client
Next, we will create a simple client using HTML and JavaScript. The client will connect to the WebSocket server, send messages, and display received messages.
Step 5: Create the HTML File
Create a new file named index.html
and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chat Application</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
.container {
max-width: 800px;
margin: auto;
background: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
}
#messages {
margin-top: 20px;
border: 1px solid #ccc;
padding: 10px;
background: #f9f9f9;
height: 200px;
overflow-y: auto;
}
input[type="text"] {
width: calc(100% - 100px);
padding: 10px;
margin-right: 10px;
}
button {
padding: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>Chat Application</h1>
<input type="text" id="messageInput" placeholder="Type a message...">
<button id="send">Send</button>
<div id="messages"></div>
</div>
<script src="app.js"></script>
</body>
</html>
This HTML file includes:
- An input field to type messages.
- A button to send messages.
- A div to display received messages.
- A link to an external JavaScript file
app.js
, which will contain our WebSocket client logic.
Step 6: Implement the WebSocket Client
Create a new file named app.js
and add the following code:
const socket = new WebSocket('ws://localhost:8000/ws');
socket.addEventListener('open', (event) => {
console.log('Connected to WebSocket server.');
document.getElementById('messages').innerHTML += '<p>Connected to WebSocket server.</p>';
});
socket.addEventListener('message', (event) => {
console.log('Message from server: ', event.data);
document.getElementById('messages').innerHTML += '<p>' + event.data + '</p>';
});
socket.addEventListener('error', (event) => {
console.error('WebSocket error: ', event);
document.getElementById('messages').innerHTML += '<p>WebSocket error: ' + event + '</p>';
});
socket.addEventListener('close', (event) => {
console.log('WebSocket closed: ', event);
document.getElementById('messages').innerHTML += '<p>WebSocket closed.</p>';
});
document.getElementById('send').addEventListener('click', () => {
const message = document.getElementById('messageInput').value;
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(message);
document.getElementById('messageInput').value = '';
}
});
In this code:
- We create a new WebSocket connection to the server at
ws://localhost:8000/ws
. - We set up event listeners to handle connection open, message, error, and close events.
- We handle the "Send" button click event to send messages to the server.
Testing the Chat Application
With the server running and the client set up, open index.html
in your browser. Type a message in the input field and click "Send". You should see the message appear in the messages div, along with any messages sent by other connected clients.
Conclusion
In this chapter, we have built a real-time chat application using WebSockets. We set up a FastAPI server to handle WebSocket connections and implemented a simple client using HTML and JavaScript. This application allows multiple users to join a chat room, send messages, and receive messages in real-time.
In the next chapter, we will discuss debugging and monitoring WebSocket applications to ensure they run smoothly and efficiently.