Idempotency Key: Aman dari Klik Ganda
Memahami idempotency key untuk mencegah duplikasi saat retry: cara kerja, penyimpanan, dan pola implementasi.
Nomor tiket yang tidak bisa dipakai dua kali
Tiket konser punya nomor unik: sobek sekali, tidak bisa dipakai masuk dua kali. Idempotency key adalah "nomor tiket" untuk request HTTP: string unik yang dikirim klien di header, menjamin request yang sama (termasuk retry) hanya dieksekusi sekali oleh server.
Kenapa ini krusial untuk pembayaran
Skenario mimpi buruk: user klik "bayar", network timeout, aplikasi retry otomatis, dan user ter-charge dua kali. Tanpa idempotency, server tidak bisa membedakan "request baru" dari "ulangan request tadi". Dengan idempotency key, retry memakai key yang sama dan server mengembalikan hasil yang sudah disimpan, bukan mengeksekusi ulang.
Contoh 1: mengirim idempotency key
POST /api/bayar HTTP/1.1
Host: toko.contoh.id
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{"order_id": 123, "nominal": 50000}Klien men-generate UUID sekali per aksi user (bukan per percobaan kirim). Kalau request timeout dan di-retry, key yang SAMA dikirim ulang.
Contoh 2: logika di sisi server
const hasilTersimpan = {};
app.post("/api/bayar", function(req, res) {
const key = req.headers["idempotency-key"];
if (hasilTersimpan[key]) {
return res.json(hasilTersimpan[key]);
}
const hasil = prosesPembayaran(req.body);
hasilTersimpan[key] = hasil;
res.json(hasil);
});Request pertama dieksekusi dan hasilnya disimpan per key. Request ulang dengan key sama langsung mengembalikan hasil tersimpan tanpa eksekusi ulang. Di production, penyimpanannya memakai Redis/database dengan TTL, bukan object di memori.
Kesalahan umum
Salah: generate key baru setiap retry. Mengalahkan tujuan idempotency. Yang benar: satu key per aksi user, dipakai ulang untuk semua retry aksi itu.
Salah: memakai idempotency untuk GET. GET sudah idempotent secara alami. Yang benar: fokuskan ke POST/operasi yang mengubah data (pembayaran, pemesanan).
Salah: menyimpan hasil selamanya. Memory bocor. Yang benar: beri TTL (misalnya 24 jam), cukup untuk jendela retry yang realistis.
Salah: key tidak unik antar user. Dua user dengan key sama bisa saling mengambil hasil. Yang benar: gabungkan key dengan identitas user, atau validasi kepemilikan.
Kapan TIDAK perlu idempotency key
Tidak semua POST butuh key. Hemat kompleksitas dengan aturan ini:
- Perlu: pembayaran, pemesanan tiket, transfer saldo, pembuatan order. Akibat duplikasi: fatal (uang hilang ganda).
- Tidak perlu: kirim komentar, like, update profil. Akibat duplikasi: ringan (komentar ganda bisa dihapus).
Tanya dirimu: "kalau request ini tereksekusi dua kali, seberapa parah?" Kalau jawabannya "sangat", pasang idempotency key. Kalau "biasa saja", retry biasa cukup.
Catatan teknis: Stripe mempopulerkan pola ini: semua request POST-nya mendukung
Idempotency-Key. Kalau kamu membangun API pembayaran atau pemesanan, tiru pola ini sejak hari pertama.
Tantangan
Tentukan kapan butuh idempotency key
Untuk tiap operasi, tentukan perlu idempotency key atau tidak + alasan:
- POST /api/bayar (pembayaran).
- GET /api/produk (ambil katalog).
- POST /api/komentar (tambah komentar).
- DELETE /api/keranjang (kosongkan keranjang).
Tulis: operasi -> perlu/tidak -> alasan satu baris.