A production-ready real-time chatting backend using FastAPI, WebSockets, Redis Pub/Sub, and PostgreSQL.
- FastAPI: Async web framework.
- WebSockets: Real-time bidirectional communication.
- Redis Pub/Sub: Horizontal scaling mechanism. Messages are published to Redis and consumed by all server instances to deliver to connected clients.
- PostgreSQL: Persistent storage for users, rooms, and messages.
- SQLAlchemy (Async): ORM for database interactions.
- Alembic: Database migrations.
- Docker: Containerization.
- JWT Authentication: Secure login and WebSocket connection validation.
- Real-time Messaging: Instant delivery via WebSockets.
- Group Chats: Room-based messaging.
- Message History: Persistent storage of all messages.
- Presence: Online/Offline status tracking (basic implementation).
- Scalable: Designed to run multiple instances behind a load balancer.
/app
/api # HTTP and WebSocket routes
/core # Config and Security
/db # Database session and base
/models # SQL models
/schemas # Pydantic schemas
/services # Business logic
/ws # WebSocket Connection Manager
main.py # Entry point
docker-compose up -dThis starts PostgreSQL and Redis.
If you don't have Docker, you can run in Standalone Mode (SQLite + InMemory PubSub).
- Dependencies: Just install the python requirements.
- Configuration: The
.envfile is already pre-configured to use SQLite (fastsock.db) and disable Redis. - Note: In this mode, horizontal scaling (multiple uvicorn instances) will not work for chat. It works for a single instance development.
Create virtual environment and install dependencies:
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txtRun migrations:
alembic revision --autogenerate -m "Initial migration"
alembic upgrade headStart the server:
uvicorn app.main:app --reloadOpen http://localhost:8000/docs to see the Swagger UI.
Endpoint: ws://localhost:8000/api/v1/ws/chat?token={access_token}
Client -> Server:
{
"event": "message.send",
"data": {
"content": "Hello World",
"receiver_id": 2, // For 1-on-1
"room_id": null // For group
}
}Server -> Client:
{
"event": "message.receive",
"data": {
"id": 1,
"content": "Hello World",
"sender_id": 1,
"timestamp": "2023-10-27T10:00:00"
}
}FastSock supports 1:1 WebRTC video calling using the existing authenticated WebSocket as the signaling channel.
Frontend fetches ICE server configuration from:
GET /api/v1/webrtc/ice-servers (requires Bearer token)
Configure servers via .env:
WEBRTC_ICE_SERVERS_JSON=[{"urls":["stun:stun.l.google.com:19302"]},{"urls":["turn:your-turn-host:3478"],"username":"user","credential":"pass"}]
All call events use event names prefixed with call. and JSON payloads under data:
call.invite{ call_id, to_user_id, room_id?, sdp_offer }call.accept{ call_id, to_user_id, sdp_answer }call.ice{ call_id, to_user_id, candidate }call.reject/call.hangup/call.busy{ call_id, to_user_id }
- Same browser profile (two users) in two windows: invite → accept → hangup
- Different networks (Wi-Fi vs hotspot): verify media connects; add TURN if it fails
- Permission denied (camera/mic blocked): ensure UI fails gracefully
- Busy handling: start a call, then receive a second invite
- Refresh during ringing and during an active call: ensure cleanup and hangup works
1:1 calls can work peer-to-peer, but group calls typically need an SFU to avoid N² bandwidth.
- Keep FastSock WebSocket for call control (join/leave/mute/raise-hand) and authentication.
- Use an SFU (e.g., LiveKit, Janus, mediasoup) for media routing.
- Replace
call.invite/accept/icepeer signaling with “create room” + “join token” flows handled by the SFU.
Run the test suite (requires pytest):
pytestA simple HTML client is provided in simple_client.html.
- Open
simple_client.htmlin your browser. - Sign up / Login.
- Connect and start chatting!