A lightweight WebSocket handler for FastAPI with connection management, rooms, and client ID routing
Project description
MR WS Handler for FastAPI
A lightweight, reusable WebSocket handler for FastAPI – developed by Moeez Raza.
The goal of this project is to make using WebSockets in FastAPI easier, simpler, and faster. Stop copying connection‑management code between projects. Just install, import, and focus on your real‑time logic.
✨ Features
- ✅ Simple connection manager – automatically handles
accept, store, and disconnect. - ✅ Broadcast to all connected clients – one line to send a message to everyone.
- ✅ Send to specific client ID – direct messaging with integer or string IDs.
- ✅ Room support – group clients into rooms and send messages to a room only.
- ✅ Multiple message types –
str,bytes,dict(auto‑converted to JSON viasend_message). - ✅ Flexible endpoint modes – choose
mode="str","bytes", or"dict"for incoming messages. - ✅ Lifecycle decorators –
@onopenand@onclosecallbacks for connection events. - ✅ Ready‑to‑use HTML/JS test client – full UI to test connections, client IDs, and rooms.
- ✅ Fully async – built for high‑performance FastAPI apps.
- ✅ Global connection manager – a single
connectionManagerinstance, accessible anywhere. - ✅ Reusable – publish to PyPI and
pip installin any project.
📦 Installation
pip install mr_wshandler_fastapi
Or install directly from GitHub:
pip install git+https://github.com/moeezraza35/mr_wshandler_fastapi.git
🚀 Quick Start
Run the demo (easiest way to test)
Clone the repository and run the included demo server:
git clone https://github.com/your-username/mr_fastapi_wshandler.git
cd mr_fastapi_wshandler
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txt
python demo/main.py
Open your browser at http://localhost:8000. You'll see a full HTML/JS test client that lets you:
- Connect to the WebSocket
- Send text or JSON messages
- Set a custom client ID
- Join / leave rooms
- See received messages in real time
📚 API Reference
WSHandler
The main entry point for your WebSocket endpoint.
WSHandler()– creates a new handler instance. It automatically uses the globalconnectionManager(no need to create one manually).@WSHandler.endpoint(mode="str")– decorator for your WebSocket route.- mode can be
"str"(default),"bytes", or"dict". - It determines how incoming messages are received and passed to your callback.
- Your callback function will receive the decoded data (string, bytes, or dict).
- mode can be
@WSHandler.onopen(optional) – decorator to register a callback that runs whenever a new WebSocket connection is accepted.
@ws.onopen
async def on_open(websocket: WebSocket):
print(f"New client connected: {websocket}")
@WSHandler.onclose(optional) – decorator to register a callback that runs when a WebSocket connection is closed (client‑ or server‑initiated).
@ws.onclose
async def on_close(websocket: WebSocket):
print(f"Client disconnected")
Note: The
onopenandonclosecallbacks are called after the connection has been added to / removed from the manager. You can accessconnectionManagerinside them to inspect active connections.
connectionManager (global instance)
The singleton that manages all active WebSocket connections. It is created automatically when you instantiate WSHandler().
Core Connection Management
| Method | Description |
|---|---|
async connect(websocket: WebSocket) |
Accepts the WebSocket and stores the connection. Called automatically by @ws.endpoint. |
async disconnect(websocket: WebSocket) |
Closes the WebSocket (server‑initiated) and removes it from the manager. |
async remove_connection(websocket: WebSocket) |
Removes a connection without closing it – used when the client has already disconnected. |
async set_client_id(websocket: WebSocket, clientId: int | str) |
Assigns a unique identifier to a connection (e.g., user ID, session ID) default is 0. |
Sending Messages
| Method | Description |
|---|---|
async send_message(message: str | bytes | dict, websocket: WebSocket) |
Core sender – automatically handles the message type (string → send_text, bytes → send_bytes, dict → send_json). Used internally by all other send methods. |
async send_message_to_connection(...) |
Alias for send_message. Sends a message to a specific connection. |
async send_message_to_client_id(message, clientId: int | str) |
Looks up the connection by clientId, then calls send_message to deliver the message. |
async broadcast(message: str | bytes | dict) |
Iterates over all active connections and calls send_message for each one. |
Room Management
Rooms allow you to group connections and send messages only to members of a specific room.
| Method | Description |
|---|---|
add_client_id_to_room(clientId: int | str, room: str) |
Adds a client (by ID) to a room. |
remove_client_id_from_room(clientId: int | str, room: str) |
Removes a client from a room. |
add_connection_to_room(websocket: WebSocket, room: str) |
Adds a connection (by WebSocket object) to a room. |
remove_connection_from_room(websocket: WebSocket, room: str) |
Removes a connection from a room. |
async send_message_to_room(message: str | bytes | dict, room: str) |
Iterates over all connections in the given room and calls send_message for each one. |
Example:
# Inside your WebSocket callback
connectionManager.add_connection_to_room(websocket, "general")
await connectionManager.send_message_to_room("Hello room!", "general")
Typical Usage Flow
from mr_wshandler import WSHandler, connectionManager
ws = WSHandler()
@ws.onopen
async def onopen(websocket):
print("New connection")
@ws.endpoint(mode="dict")
async def onMessage(data: dict, websocket: WebSocket):
if "room" in data:
# Join a room
connectionManager.add_connection_to_room(websocket, data["room"])
await connectionManager.send_message_to_room(f"{websocket} joined", data["room"])
else:
# Broadcast to all
await connectionManager.broadcast(data)
🧪 Testing
Run the included demo server to test all features:
python demo/main.py
Then open http://localhost:8000 in your browser. The HTML test client lets you connect, send messages, set client IDs, and join/leave rooms – all interacting with your WebSocket module in real time.
🤝 Contributing
Contributions, bug reports, and feature requests are warmly welcome! Feel free to open issues or submit pull requests.
If you fork this repository, please include a note in your README or documentation that your project is based on mr_wshandler_fastapi by Moeez Raza. A simple line like "Originally forked from mr_fastapi_wshandler by Moeez Raza" is appreciated.
📄 License
This project is licensed under the MIT License – see the LICENSE.md file for details.
The MIT License already requires that the original copyright notice (© Moeez Raza) be retained in all copies or substantial portions of the software.
🔗 References
Made with ❤️ by Moeez Raza
Tags: python fastapi websocket socket-server real-time
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mr_wshandler_fastapi-0.1.1.tar.gz.
File metadata
- Download URL: mr_wshandler_fastapi-0.1.1.tar.gz
- Upload date:
- Size: 4.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
427ec88047b1fa7f03b20bf392a84a24ac70c0c312dddbdee9fc63a2167e958c
|
|
| MD5 |
4bf153026d8855de324a579188bbfa41
|
|
| BLAKE2b-256 |
01b59b65b0fc4caed472f852245d12f0da5889e2b84cda9b98447bdbedb00c6c
|
File details
Details for the file mr_wshandler_fastapi-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mr_wshandler_fastapi-0.1.1-py3-none-any.whl
- Upload date:
- Size: 5.3 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea5e6762206d60091475d74303fd3e4b4ae68f994b5fdcefd83c87c83f3e5ffa
|
|
| MD5 |
2afabfe833fb6de87a189ab3e5b24f0e
|
|
| BLAKE2b-256 |
d0d588c678ed6d552fa109f1da8741d055aace206114fba9e3cabc7feef3efc6
|