name: backend-dev description: Utilisez cette compétence pour le développement backend — logique serveur, authentification, microservices, fonctions serverless, middleware, tâches d'arrière-plan, stratégies de mise en cache et modèles d'architecture backend. Déclencheurs : backend, serveur, endpoint API, middleware, authentification, autorisation, microservice, serverless, tâche d'arrière-plan, file d'attente, mise en cache, session.
Développement Backend
Principes Fondamentaux
- Services sans état — ne stockez pas l'état de session en mémoire ; utilisez Redis ou une base de données.
- Échec rapide — validez les entrées à la frontière, renvoyez les erreurs tôt.
- Idempotence — endpoints POST/PUT pouvant être appelés plusieurs fois en toute sécurité.
- Observabilité — chaque service nécessite des logs, des métriques et des traces.
Structure des Endpoints API
Cycle de Vie d'une Requête
Requête → Limitation de débit → Authentification → Autorisation → Validation → Logique métier → Réponse
Ne sautez jamais cet ordre. Authentification avant logique métier. Validation avant traitement.
Normes de Réponse
// Succès
{ "data": { ... }, "meta": { "page": 1, "total": 100 } }
// Erreur
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Description lisible par l'humain",
"details": [{ "field": "email", "issue": "Format invalide" }]
}
}
Modèles d'Authentification
Bonnes Pratiques JWT
- TTL court du token d'accès (15 min) + long token de rafraîchissement (7 jours).
- Stockez le token de rafraîchissement dans un cookie httpOnly (pas dans localStorage).
- Validez la signature, l'expiration, l'émetteur et le public.
- Alternez les tokens de rafraîchissement lors de l'utilisation.
- Maintenez une liste de révocation ou utilisez uniquement des tokens à courte durée de vie.
Authentification par Session
- Stockez l'ID de session dans un cookie httpOnly, Secure, SameSite.
- Stockez les données de session dans Redis avec TTL.
- Régénérez l'ID de session après connexion (prévention de fixation de session).
Autorisation
// Vérifiez l'autorisation au niveau de la couche service, pas seulement de la route
async function getOrder(userId: string, orderId: string) {
const order = await db.orders.findById(orderId)
if (!order) throw new NotFoundError()
// Vérification d'autorisation — l'utilisateur ne peut voir que ses propres commandes
if (order.userId !== userId) throw new ForbiddenError()
return order
}
Tâches d'Arrière-Plan et Files d'Attente
Utilisez des files d'attente pour :
- L'envoi d'e-mails.
- Le traitement d'images/fichiers.
- Les appels API externes qui n'ont pas besoin d'être synchrones.
- Les tâches longues.
Modèles de Tâches
Lancer-et-oublier : Mettre en file d'attente et retourner immédiatement
Planifiée : Exécuter à une heure spécifique (cron)
Différée : Exécuter après X minutes/heures
Réessayer : Réessayer en cas d'échec avec backoff
Implémentez toujours :
- Une file de lettres mortes pour les tâches échouées.
- Une clé d'idempotence pour éviter le traitement en double.
- Un délai d'attente par tâche.
- Un nombre maximal de tentatives.
Gestion des Erreurs
// Hiérarchie d'erreurs structurée
class AppError extends Error {
constructor(
public message: string,
public statusCode: number,
public code: string
) { super(message) }
}
class ValidationError extends AppError {
constructor(details: ValidationDetail[]) {
super('Échec de la validation', 400, 'VALIDATION_ERROR')
this.details = details
}
}
// Gestionnaire d'erreurs global
app.use((err, req, res, next) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({ error: err })
}
// Journaliser les erreurs inattendues
logger.error('Erreur inattendue', { err, req })
res.status(500).json({ error: { code: 'INTERNAL_ERROR' } })
})
Liste de Vérification du Middleware
Toute API de production a besoin de :
- Journalisation des requêtes (méthode, chemin, statut, durée).
- Limitation de débit (par IP, par utilisateur, par endpoint).
- Configuration CORS (liste blanche explicite).
- Helmet / en-têtes de sécurité.
- Propagation de l'ID de requête (pour le tracing distribué).
- Limites de taille du corps.
- Gestion du délai d'attente.
Configuration de l'Environnement
// Ne jamais coder en dur la configuration — toujours depuis l'environnement
const config = {
db: {
url: process.env.DATABASE_URL, // requis
poolSize: parseInt(process.env.DB_POOL_SIZE ?? '10')
},
jwt: {
secret: process.env.JWT_SECRET, // requis
expiresIn: process.env.JWT_TTL ?? '15m'
}
}
// Valider la configuration requise au démarrage — échec rapide
const required = ['DATABASE_URL', 'JWT_SECRET']
for (const key of required) {
if (!process.env[key]) throw new Error(`Variable d'environnement requise manquante : ${key}`)
}