Sécurité
Bonnes pratiques — Performance & Observabilité
Cache, refresh proactif, pagination, TanStack Query, métriques Prometheus et structured logging.
Version v1.03 min de lecture
Bonnes pratiques — Performance & Observabilité
Ce chapitre couvre les patterns de performance, de cache et d'observabilité. Lisez Bonnes pratiques sécurité en complément.
Performance
9. Cacher /me — un seul appel au login
typescript// BIEN : stocker dans un React context, ne jamais re-fetcher à la navigation const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); useEffect(() => { // Appelé une seule fois au mount du provider (= au login) fetchMe().then(setUser); }, []); return <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>; }; // MAL : re-fetcher /me à chaque page/composant const UserPage = () => { const { data: user } = useQuery({ queryKey: ["me"], queryFn: fetchMe }); // refetch sur chaque mount };
10. Refresh proactif avant l'expiration
typescript// BIEN : vérifier exp - now < 60s et rafraîchir avant l'expiration const REFRESH_THRESHOLD = 60; // secondes function scheduleTokenRefresh(expiresIn: number) { const refreshIn = Math.max(0, expiresIn - REFRESH_THRESHOLD) * 1000; setTimeout(async () => { await refreshTokens(); }, refreshIn); } // MAL : rafraîchir après un 401 (le call a déjà échoué, UX dégradée) catch (err) { if (err.status === 401) await refreshTokens(); // trop tard }
11. Pagination — ne jamais charger tout
typescript// BIEN : paginer, limit max = 100 const { data } = await apiGet("config/users", { page: "1", limit: "50" }); // MAL : tenter de tout charger const { data } = await apiGet("config/users", { page: "1", limit: "10000" }); // timeout
12. TanStack Query — staleTime adapté à la criticité
typescript// Données qui changent rarement (branding, runtime-config) : 5 minutes useQuery({ queryKey: ["runtime-config"], queryFn: fetchRuntimeConfig, staleTime: 5 * 60 * 1000, }); // Données qui changent souvent (users, invitations) : 30s useQuery({ queryKey: ["users", page], queryFn: () => fetchUsers(page), staleTime: 30_000, });
Architecture
13. Proxy serveur pour tous les appels API
Le browser ne doit jamais appeler directement la Public API.
textBrowser → /api/proxy/[...path] (route Next.js) → Public API └── lit les cookies HttpOnly └── ajoute Authorization + x-enriched-token └── forward la réponse
14. Séparer Discovery et API
typescript// BIEN : Discovery utilisé une seule fois, avant l'auth const { keycloakUrl } = await discoverStartLogin({ host }); window.location.assign(keycloakUrl); // MAL : appeler Discovery après chaque login ou sur chaque page useEffect(() => { fetchDiscovery(email); // inutile après auth }, []);
15. Respecter la hiérarchie dans votre modèle de données
typescript// Vos entités doivent refléter la hiérarchie Wakastart interface AppContext { partnerId: string; // pid du wakaToken networkId: string; // nid customerId: string; // cid appId: string; // votre app (WID) }
16. Utiliser les WIDs dans les URLs
textBIEN : /users/WKST05 (lisible, stable) MAL : /users/550e8400-... (UUID interne)
Observabilité
17. Propager le x-trace-id
typescript// Inclure l'ID de trace dans toutes vos requêtes API const traceId = crypto.randomUUID(); headers["x-trace-id"] = traceId; // Logger côté frontend avec le même ID logger.info("API call", { traceId, url, method });
18. Métriques recommandées
Exposez des métriques Prometheus depuis votre Wakapp :
textwakapp_api_calls_total{endpoint, status} wakapp_token_refresh_total{success} wakapp_invitations_created_total{customer} wakapp_invitations_accepted_total{customer} wakapp_auth_flow_duration_seconds (histogram)
19. Structured logging
typescript// BIEN : JSON structuré, parsable par Loki / CloudWatch logger.info({ event: "user_login_success", userId: user.wid, customerId: user.customer.wid, adminLevel: user.adminLevel, duration_ms: Date.now() - startTime, }); // MAL : texte libre impossible à filtrer console.log(`User ${email} logged in successfully in ${elapsed}ms`);
Checklist performance pré-production
- Refresh proactif implémenté (threshold 60s)
- Rate limit géré (backoff exponentiel)
- /me chargé une fois, mis en cache, invalidé au refresh
- runtime-config chargé une fois au démarrage
- TanStack Query configuré avec des
staleTimeadaptés - Pagination correcte (limit ≤ 100)
-
x-trace-idpropagé dans tous les appels API
Aller plus loin
- Headers & Rate limits : backoff exponentiel détaillé
- Pièges classiques : diagnostic des problèmes de performance