HTTP Caching Strategy¶
Vue d'ensemble¶
Stratégie de cache HTTP multi-niveaux pour optimiser la bande passante, réduire la latence et améliorer l'expérience utilisateur.
Architecture¶
| Text Only | |
|---|---|
Middleware: CacheControlMiddleware¶
Injecte automatiquement les headers Cache-Control selon le verbe HTTP et le type de ressource.
Configuration (_sample/config/http.yaml):
| YAML | |
|---|---|
Configuration via CLI:
| Bash | |
|---|---|
Les valeurs doivent être positives ou nulles. get_list_max_age: 0 transforme les réponses
collection en no-store, utile pour les listes temps-réel. Un TTL plus long réduit la latence et
la bande passante, mais augmente la durée pendant laquelle l'utilisateur peut voir une donnée
ancienne sans revalidation.
Stratégie par verbe¶
| Verbe | Ressource | Directive | Raison |
|---|---|---|---|
| GET | Single (/{uuid}) |
private, max-age=300 |
Cacheable 5min par le client, pas le CDN (données potentiellement user-specific) |
| GET | Collection (/) |
private, max-age=60 |
Shorter TTL (1min) car changements fréquents |
| POST | Create | no-cache, no-store, must-revalidate |
Jamais cacher les mutations |
| PUT/PATCH | Update | no-cache, no-store, must-revalidate |
Jamais cacher les mutations |
| DELETE | Delete | no-cache, no-store, must-revalidate |
Jamais cacher les mutations |
| HEAD/OPTIONS | Metadata | public, max-age=86400 |
Cacheable 24h par tout le monde |
Si une route définit déjà Cache-Control, le middleware ne l'écrase pas. Cela permet de garder une
politique spécifique sur un endpoint sans contourner le câblage transverse.
Heuristique ressource unique vs collection¶
Le middleware détecte automatiquement le type de ressource via le path:
/v1/ingredients/01951234-5678-7abc→ Single (UUID pattern)/v1/ingredients→ Collection/v1/ingredients/search→ Collection (action/filter)
Code:
| Python | |
|---|---|
Directives Cache-Control¶
private vs public¶
private — Cacheable uniquement par le client (browser/app), pas par les proxies intermédiaires.
- Utilisé quand: données user-specific (commandes, profil utilisateur)
- Example:
Cache-Control: private, max-age=300
public — Cacheable par tout le monde (client, CDN, reverse proxy).
- Utilisé quand: données statiques/publiques (produits, assets)
- Example:
Cache-Control: public, max-age=3600
Dans _sample: Toutes les ressources utilisent private car potentiellement multi-tenant.
max-age — TTL en secondes¶
Durée pendant laquelle la réponse est considérée "fraîche" sans revalidation.
Recommandations par type: | Type | TTL | Justification | |---|---|---| | Entité mutable (ingredient, recipe) | 300s (5min) | Balance fraîcheur/performance | | Collection filtrée | 60s (1min) | Changements fréquents | | Metadata statique (OPTIONS) | 86400s (24h) | Rarement modifié | | Assets statiques (non géré par FastAPI) | 31536000s (1 an) | Immutable |
no-cache vs no-store¶
no-cache — Doit revalider avant utilisation (If-None-Match).
- Header:
Cache-Control: no-cache - Utilisé quand: données sensibles mais cacheable avec revalidation
no-store — Jamais stocker en cache (même pas localement).
- Header:
Cache-Control: no-cache, no-store, must-revalidate - Utilisé quand: mutations (POST/PUT/PATCH/DELETE)
Dans _sample: Mutations utilisent no-cache, no-store, must-revalidate pour éviter tout cache.
Intégration avec ETag¶
Le cache HTTP est plus efficace couplé avec ETag (RFC 7232).
Dans Arclith, ETaggerMiddleware s'applique aux réponses GET JSON 2xx qui exposent un champ
version ou data.version. Les POST, PUT, PATCH et DELETE ne reçoivent pas de header de
cache en sortie; If-Match sur PUT/PATCH reste disponible côté requête pour l'optimistic
locking applicatif.
Workflow:
-
Première requête:
-
Requête dans les 5min (cache fresh):
- Client utilise la réponse cachée localement (aucune requête réseau)
-
Requête après 5min (cache stale):
Text Only
Bénéfices:
- Bande passante: 304 évite le transfert du body
- Latence: Réponse plus rapide (header-only)
- Concurrency: If-Match empêche les lost updates
Configuration par environnement¶
Développement (config/http.yaml)¶
| YAML | |
|---|---|
Staging¶
Production¶
| YAML | |
|---|---|
Note: Pour les données temps-réel (stocks, prix), utiliser get_list_max_age: 0 (no-store).
CDN / Reverse Proxy (nginx)¶
Si l'API est derrière un CDN, les directives private empêchent le cache partagé.
Pour activer le cache CDN (données publiques uniquement):
-
Modifier la stratégie middleware:
-
Configuration nginx:
Monitoring¶
Headers à surveiller:
X-Cache(nginx/CDN) — HIT/MISS/BYPASSAge(nginx/CDN) — Âge du cache en secondesX-Process-Time-Ms(arclith) — Temps de traitement API
Métriques:
cache_hit_rate(CDN) — % de requêtes servies depuis le cachebackend_requests_per_second(API) — Doit diminuer si cache efficace304_responses_per_second(API) — ETag revalidations
Cas d'usage E-commerce¶
1. Catalogue produits (lecture intensive)¶
Problème: 10k requêtes/s pour afficher les produits.
Solution:
| Text Only | |
|---|---|
Résultat: 95% cache hit ratio CDN → API ne reçoit que 500 req/s.
2. Stock temps-réel (écriture intensive)¶
Problème: Stock change à chaque vente → cache stale = bad UX.
Solution:
Résultat: Toujours fresh, mais charge serveur élevée → utiliser WebSocket/SSE pour push.
3. Panier utilisateur (user-specific)¶
Problème: Données sensibles, ne jamais cacher par le CDN.
Solution:
Résultat: Client peut rafraîchir localement, mais chaque user hit l'API.
Désactivation sélective¶
Désactiver pour un endpoint spécifique:
| Python | |
|---|---|
Désactiver globalement:
Références¶
- RFC 7234: Caching
- MDN: Cache-Control
- Google Web Fundamentals: HTTP Caching