FastAPI Dependency Cache Fix
In this tutorial, you'll learn about FastAPI Dependency Cache Fix. We cover key concepts, practical examples, and best practices.
The Problem
FastAPI dependencies run on every request. For expensive operations like database lookups, API calls, or permission checks, this adds unnecessary latency.
Quick Fix
Wrong — dependency runs on every request
from fastapi import Depends, FastAPI
app = FastAPI()
async def get_current_user(token: str):
# Database query on every request
user = await db.query(User).filter(User.token == token).first()
return user
@app.get("/profile")
async def profile(user=Depends(get_current_user)):
return user
Output: The database is queried on every single request, even when the user hasn't changed.
Correct — cache with dependency
from fastapi import Depends, FastAPI, HTTPException
from functools import lru_cache
@lru_cache(maxsize=128)
def get_settings():
return Settings()
@app.get("/config")
async def config(settings: Settings = Depends(get_settings)):
return settings
Output: Settings loaded once and cached. Subsequent requests use cached value.
Request-scoped cache
from fastapi import Request, Depends
async def get_db(request: Request):
if not hasattr(request.state, 'db'):
request.state.db = Database()
return request.state.db
@app.get("/items")
async def items(db=Depends(get_db)):
return await db.fetch_all("SELECT * FROM items")
Redis-backed dependency cache
import json
from fastapi import Depends
from redis import asyncio as aioredis
async def get_cached_user(user_id: int):
redis = await aioredis.from_url("redis://localhost")
cache_key = f"user:{user_id}"
cached = await redis.get(cache_key)
if cached:
return json.loads(cached)
user = await fetch_user_from_db(user_id)
await redis.setex(cache_key, 300, json.dumps(user.dict()))
return user
Cache with TTL
from functools import lru_cache
from datetime import datetime, timedelta
class TimedCache:
def __init__(self, seconds: int = 60):
self.seconds = seconds
self.cache = {}
self.timestamps = {}
def get(self, key: str):
if key in self.cache:
if datetime.now() - self.timestamps[key] < timedelta(seconds=self.seconds):
return self.cache[key]
return None
def set(self, key: str, value):
self.cache[key] = value
self.timestamps[key] = datetime.now()
cache = TimedCache(seconds=30)
async def get_expensive_data(dep=Depends(some_dep)):
key = "expensive_data"
cached = cache.get(key)
if cached:
return cached
data = await compute_expensive()
cache.set(key, data)
return data
Prevention
- Use
lru_cachefor true singleton dependencies (settings, configs). - Use
request.statefor request-scoped caching. - Use Redis for cross-process, cross-server caching.
- Always set TTL to prevent stale data.
Common Mistakes with dependency cache
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
- Using
returnto exit a function early instead of wrapping a pure value in the monad
These mistakes appear frequently in real-world FASTAPI code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro