Real-world Applications and Projects
Apply your knowledge in practical projects to build real-world applications using FastAPI.
Content
Creating a Chat Application
Versions:
Watch & Learn
AI-discovered learning video
Sign in to watch the learning video for this topic.
Creating a Chat Application with FastAPI — A Chaotic-but-Useful Guide
Want to build a chat app that actually works under real-world load, doesn't leak memory, and won't crash when Karen opens 20 tabs? Good. Let's do that.
This guide assumes you already built a RESTful API and learned deployment strategies like serverless options and scaling FastAPI apps. We're going to build on that — focusing on the parts that make chat apps special: real-time comms, message persistence, delivery guarantees, and scaling without buying a supercomputer.
What makes a chat app different? (Spoiler: sockets, state, and chaos)
- Real-time updates: clients expect near-instantaneous messages.
- Many open connections: each user may hold a WebSocket connection.
- Ordering and persistence: messages must be stored and sometimes replayed.
- Broadcasting: messages sent by one client often must reach many others.
FastAPI gives us ASGI power for real-time. The rest is architecture.
High-level architecture (the components you will actually care about)
- FastAPI app (ASGI server: uvicorn or hypercorn) — handles WebSocket endpoints, REST endpoints (auth, history, health), and background tasks.
- Database (Postgres) — persistent message history, user records.
- Message broker / shared memory (Redis with Pub/Sub, or Kafka/RabbitMQ) — across instances to broadcast messages.
- Frontend (React/Vue/Svelte) — connects via WebSocket; falls back to long-poll when necessary.
- Load balancer (NGINX / Cloud LB) or managed service. Sticky sessions only if you avoid broker-based publish/subscribe.
- Optional: WebSocket gateway for serverless (API Gateway WebSocket, or a managed WS proxy).
Step-by-step: Minimal viable chat with FastAPI
1) Models and schemas
Use Pydantic for validation. Keep the schema small and honest.
from pydantic import BaseModel
from datetime import datetime
class MessageIn(BaseModel):
room_id: int
content: str
class MessageSaved(BaseModel):
id: int
room_id: int
user_id: int
content: str
created_at: datetime
2) WebSocket endpoint (basic)
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket('/ws/{room_id}')
async def ws_room(websocket: WebSocket, room_id: int):
await websocket.accept()
try:
while True:
data = await websocket.receive_json()
# validate, save to DB, publish to broker
await websocket.send_json({'ok': True})
except Exception:
await websocket.close()
This works for a single server, single process demo. For anything real, you need a broker.
3) Publish/Subscribe with Redis (recommended for many setups)
- When a message arrives on any server, save to Postgres and publish to Redis channel for that room.
- Each server subscribed to that redis channel broadcasts to connected WebSocket clients.
# pseudocode
await redis.publish(f'room:{room_id}', json.dumps(message_payload))
# subscriber loop on each server listens and forwards to connected websockets
Real-world concerns & patterns
Authentication & authorization
- Use OAuth2 / JWT for REST and include token during WebSocket handshake.
- Validate token on connect and map connection to user id.
Persistence and ordering
- Save messages in DB with timestamps and increasing ids.
- For ordering, prefer server-assigned ids/timestamps instead of trusting client order.
Delivery guarantees
- Best-effort: send messages and rely on client ACKs for critical flows.
- For guaranteed delivery, implement message status (sent/delivered/read) and retry logic.
Scaling connections
- Each FastAPI process holds many async connections; scale horizontally.
- Use Redis or Kafka so no single server needs to know all active clients.
- Monitor file descriptors and memory per worker.
Small reminder from previous lesson: serverless can be tricky with WebSockets. Managed API Gateway WebSockets or proprietary solutions are required — you can't just slap a Lambda behind a plain WebSocket and expect smooth sailing.
Deploying and scaling (building on the 'Scaling FastAPI Applications' and 'Serverless Deployment' lessons)
- For traditional deployments: containerize with Docker, run uvicorn with multiple workers (or use an ASGI server that supports many connections), put a reverse proxy in front for TLS & static files.
- Use Redis clusters for Pub/Sub to avoid bottlenecks.
- Kubernetes + Horizontal Pod Autoscaler for horizontal scaling; use a Headless Service or external proxy to route WebSocket traffic.
- Serverless option: use managed WebSocket services (API Gateway WebSocket, Vercel/Cloudflare Workers for limited flows) but expect complexity for persistent connections and heavy traffic.
Quick table: WebSocket approach pros/cons
| Approach | Pros | Cons |
|---|---|---|
| Single server WS | Simple | Not scalable, single point of failure |
| Redis Pub/Sub + multiple servers | Scales horizontally, familiar | Redis becomes chokepoint if not sized properly |
| Kafka/RabbitMQ | High throughput, persistence | More operational complexity |
| Serverless WebSocket | Managed, autoscaling | Cold starts, vendor locks, limited connection counts |
Extras that make life less miserable
- Use BackgroundTasks for non-blocking DB writes if you need quick responses.
- Implement a max connections per user and global rate limiting to prevent abuse.
- Use JWT refresh flow and short-lived tokens for WS.
- Test with load tools (wrk, custom async scripts) and simulate many WS clients.
- Add metrics (Prometheus) for open connections, message throughput, error rates.
Testing strategy
- Unit test REST endpoints with pytest and httpx.
- For WebSockets, use pytest-asyncio + websockets or httpx/anyio to test connect/send/receive flows.
- End-to-end: spin up a test Redis + Postgres and run a small cluster locally (docker-compose), then run realistic scenarios.
Closing: Key takeaways (so you remember this at 3 AM)
- Use WebSockets for real-time, but pair them with a broker (Redis/Kafka) so you can scale horizontally.
- Persist messages in a DB, not just in-memory — you'll thank yourself at GDPR audit time.
- Security and rate limits are not optional. Protect the handshake and throttle users.
- Serverless is possible but special — treat it as a separate deployment model with its own tradeoffs.
Build incrementally: get a single-process WebSocket chat running locally, add Redis Pub/Sub, then scale via containers/Kubernetes. You learned about REST and deployment earlier — now you're applying those pieces to make something real.
Go forth, build a chat that survives group chats, exes, and memes. If you want, I can drop a full starter repo with Dockerfile, docker-compose, FastAPI app, and a tiny React client — ready to ship chaos to production.
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!