Qu'est-ce que l'idempotence et pourquoi est-elle essentielle ?
L'idempotence est une propriété des opérations qui garantit qu'une requête identique exécutée plusieurs fois produit le même résultat que la première exécution, sans effets de bord supplémentaires. Par exemple :
- GET /stock : Récupérer le niveau de stock ne modifie pas les données, même après 10 appels.
- PUT /stock/123 : Mettre à jour le stock d'un produit avec la même valeur ne change rien après la première exécution.
- DELETE /order/456 : Supprimer une commande déjà supprimée ne génère pas d'erreur.
En revanche, les méthodes POST et PATCH ne sont pas idempotentes par défaut :
- POST /invoice : Créer une facture deux fois génère deux factures identiques.
- PATCH /stock : Appliquer la même mise à jour de stock deux fois peut fausser les données (ex. : décrémenter le stock deux fois au lieu d'une).
Les méthodes HTTP idempotentes par définition sont GET, HEAD, PUT, DELETE et OPTIONS . Pour rendre POST et PATCH idempotents, on utilise des mécanismes comme le header Idempotency-Key .
Cas d'usage critiques
L'idempotence est cruciale pour :
- La facturation : Éviter de créer deux fois la même facture après un timeout réseau.
- La gestion des stocks : Empêcher une mise à jour de stock de s'appliquer en double (ex. : décrémenter le stock deux fois pour une même commande).
- Les paiements : Bloquer les prélèvements en double lors d'une réexécution de requête.
- Les réservations de ressources : Garantir qu'une ressource (ex. : créneau de livraison) n'est réservée qu'une seule fois.
Méthodes HTTP idempotentes vs non idempotentes
| Méthode | Idempotente ? | Exemple d'usage | Risque sans idempotence |
|---|---|---|---|
| GET | ✅ Oui | Récupérer une liste de produits. | Aucun (lecture seule). |
| HEAD | ✅ Oui | Vérifier l'existence d'une ressource sans la télécharger. | Aucun. |
| PUT | ✅ Oui | Mettre à jour un produit avec des données complètes. | Aucun (remplace entièrement la ressource). |
| DELETE | ✅ Oui | Supprimer une commande. | Aucun (suppression idempotente). |
| POST | ❌ Non | Créer une facture. | Création de doublons (ex. : deux factures identiques). |
| PATCH | ❌ Non (sauf si mécanismes ajoutés) | Mettre à jour partiellement un stock. | Mise à jour appliquée plusieurs fois (ex. : décrémenter le stock deux fois). |
Pour POST et PATCH, l'idempotence nécessite un mécanisme externe comme le header Idempotency-Key. Par exemple, un PATCH /stock répété peut appliquer plusieurs fois la même mise à jour sauf si un header Idempotency-Key est utilisé pour bloquer les doublons .
Exemple avec n8n : workflow pour bloquer les doublons de webhooks
Les fournisseurs de webhooks (ex. : Stripe, Shopify) utilisent une livraison at-least-once : si une requête échoue ou timeout, ils la réessaient. Cela peut déclencher deux fois le même workflow dans n8n, avec des effets de bord indésirables (ex. : deux factures créées).
Solution : un workflow n8n avec vérification d'idempotence
Le template n8n suivant « Prevent Duplicate Webhook Executions » ajoute une vérification d'idempotence avant d'exécuter des effets de bord :
- Réception du webhook : Le workflow extrait une clé d'idempotence depuis le payload (ex. :
event.id). - Vérification en base de données : Le workflow interroge une base SQLite pour vérifier si la clé existe déjà.
- Si la clé n'existe pas : Le workflow enregistre la clé et exécute les effets de bord (ex. : création de facture).
- Si la clé existe : Le workflow s'arrête pour éviter les doublons et répond avec un
200 OKpour éviter les réessais du fournisseur .
Note : Ce code suppose une base de données SQLite pour stocker les clés d'idempotence .
Extrait de code clé
// Vérification de l'existence de la clé d'idempotence
await db.run(
"INSERT INTO idempotency_keys (key, created_at) VALUES (?, ?)",
[idempotencyKey, new Date().toISOString()]
);
// Si la clé existe déjà, SQLite lèvera une erreur (UNIQUE constraint)
// Le workflow s'arrête ici pour éviter les doublons
Le workflow répond immédiatement avec un 200 OK pour éviter que le fournisseur de webhook ne réessaie la requête, même si la clé existe déjà et que le workflow est bloqué .
Cas d'usage avec le template
- Facturation : Bloquer la création de deux factures identiques après un timeout réseau.
- Gestion des stocks : Empêcher une mise à jour de stock de s'appliquer en double (ex. : décrémenter le stock deux fois pour la même commande).
- Paiements : Éviter les prélèvements en double lors d'une réexécution de requête.
Cas d'usage : Shopify et Stripe
Shopify : sécuriser les paiements et la facturation
Shopify utilise des clés d'idempotence pour les requêtes impliquant des paiements, des tentatives de facturation ou des captures de revenus. Par exemple :
- La mutation
subscriptionBillingAttemptCreateaccepte une clé d'idempotence pour éviter de créer deux tentatives de facturation identiques . - Shopify recommande d'utiliser des identifiants uniques comme des UUID aléatoires pour éviter les collisions .
Stripe : éviter les doublons de paiement
Stripe prend en charge l'idempotence pour les requêtes POST via le header Idempotency-Key. Voici comment cela fonctionne :
- Stripe conserve le statut et le corps de la réponse d'une première requête pour une clé donnée .
- Si la même clé est réutilisée dans les 24 heures, Stripe renvoie la même réponse sans réexécuter la requête .
- Après 24 heures, une nouvelle requête est générée si la clé est réutilisée .
Bonnes pratiques pour générer et gérer les clés d'idempotence
1. Génération des clés
- Format : Utilisez des UUID v4 aléatoires (ex. :
550e8400-e29b-41d4-a716-446655440000) pour éviter les collisions . - Durée de validité : Limitez la durée de validité des clés (ex. : 24 heures chez Stripe) pour éviter les conflits après expiration .
- Stockage : Stockez les clés dans une base de données avec un index UNIQUE pour garantir l'unicité.
2. Gestion des erreurs
Le serveur peut retourner les erreurs suivantes en cas de problème :
400 Bad Request: Le headerIdempotency-Keyest absent pour une opération qui le requiert.409 Conflict: Une requête avec la même clé est déjà en cours de traitement.422 Unprocessable Content: La clé est réutilisée avec un payload différent.
3. Alternatives à l'Idempotency-Key (recommandation éditoriale)
Si le header Idempotency-Key n'est pas supporté, vous pouvez utiliser :
- Clés naturelles : Utilisez un identifiant unique déjà présent dans le payload (ex. :
order_id). - Verrous optimistes : Ajoutez un champ
versionà vos ressources et rejetez les mises à jour si la version ne correspond pas.
Quand l'idempotence ne suffit pas
L'idempotence est efficace pour les opérations simples, mais elle a des limites :
- Workflows complexes : Pour des processus impliquant plusieurs services (ex. : réservation + paiement + notification), un pattern comme SAGA (transactions distribuées) peut être nécessaire.
- Effets de bord non techniques : L'idempotence ne résout pas les problèmes métier (ex. : un email envoyé deux fois malgré une clé d'idempotence).
Conclusion
L'idempotence est un mécanisme simple mais puissant pour éviter les doublons dans vos workflows automatisés. En suivant les bonnes pratiques décrites ici — utilisation d'UUID aléatoires, gestion des erreurs, et limitation de la durée de validité des clés — vous pouvez sécuriser des opérations critiques comme la facturation ou la gestion des stocks.
Pour aller plus loin :
- Testez le template n8n pour bloquer les doublons de webhooks.
- Consultez la documentation MDN sur le header
Idempotency-Key. - Explorez les comparaisons d'outils d'automatisation pour choisir la solution adaptée à vos besoins.