Project: MongoDB + Redis + API Deploy
Introduction
This capstone wires MongoDB (source of truth), Redis (cache-aside), and a FastAPI service in Docker Compose. Reads hit Redis when warm; writes update MongoDB and invalidate cache. Health checks prove the stack is ready before traffic arrives.
Prerequisites
- PyMongo With FastAPI
- Performance and Monitoring
- FastAPI Docker and CI
- Redis caching patterns
- Linux Docker introduction
Architecture
Client → FastAPI (api) → Redis (cache)
↓ miss
MongoDB (mongo)Write path: MongoDB first, then DEL cache key.
docker-compose.yml
Environment Settings
app/core/config.py:
class Settings(BaseSettings):
mongodb_uri: str = "mongodb://127.0.0.1:27017"
mongodb_db_name: str = "hello_demo"
redis_url: str = "redis://127.0.0.1:6379/0".env.example (commit this, not .env):
MONGODB_URI=mongodb://127.0.0.1:27017
MONGODB_DB_NAME=hello_demo
REDIS_URL=redis://127.0.0.1:6379/0Warning
Do not commit .env files with production credentials.
Lifespan: Mongo + Redis
Health Check
from fastapi import APIRouter, Request
from app.db.mongo import get_database
router = APIRouter()
@router.get("/health")
def health(request: Request):
get_database().command("ping")
request.app.state.redis.ping()
return {"status": "ok"}Kubernetes/load balancers call /health before routing.
Cache-Aside Read
TTL 300 seconds—tune per SLA.
Write + Invalidate
@router.patch("/posts/{post_id}")
def update_post(post_id: str, body: dict, request: Request):
if not ObjectId.is_valid(post_id):
raise HTTPException(status_code=400, detail="Invalid id")
result = get_posts_collection().update_one(
{"_id": ObjectId(post_id)},
{"$set": body},
)
if result.matched_count == 0:
raise HTTPException(status_code=404, detail="Not found")
request.app.state.redis.delete(f"post:{post_id}")
return {"updated": True}Also delete post:slug:{slug} if you cache by slug.
Dockerfile (Minimal)
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]requirements.txt: fastapi, uvicorn, pymongo[srv], redis, pydantic-settings.
Run
docker compose up --build
curl -s http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/posts/507f1f77bcf86cd799439011Second request should be faster (Redis hit)—verify with redis-cli MONITOR locally.
Production Notes
| Topic | Action |
|---|---|
| Secrets | Docker secrets or env from orchestrator |
| MongoDB auth | Create app user — Security |
| TLS | Atlas or reverse proxy — Nginx HTTPS |
| Replica set | Required for transactions; recommended for prod — Replica Sets |
| CI | pytest + compose in GitHub Actions — Git CI |
Post-Project Checklist
-
docker compose uppasses health checks - Cache hit on repeated GET
- PATCH invalidates cache
- MongoDB data survives
docker compose down(volume)
FAQ
Cache stampede?
Use short TTL + single-flight lock in Redis — Redis patterns.
Motor async API?
Swap PyMongo for Motor — chapter 21; keep same Redis pattern.
Write-through instead?
Update Redis and MongoDB in one handler—simpler reads, riskier inconsistency on partial failure.
Atlas + ElastiCache?
Same code; change URIs and security groups — Atlas.
Nginx in front?
Terminate TLS at Nginx, proxy to api:8000 — FastAPI deploy.