Idempotency adalah sifat sebuah operasi yang hasilnya tetap sama meskipun dijalankan berkali-kali. Konsep ini sangat penting dalam REST API. Tanpanya, satu request yang terkirim ulang bisa menagih pelanggan dua kali atau membuat data ganda.
Artikel ini membahas pengertian idempotency, alasan pentingnya, metode HTTP yang mendukungnya, dan cara menerapkannya lewat Idempotency-Key.
Apa Itu Idempotency?
Dalam matematika, operasi disebut idempotent jika hasilnya tidak berubah saat diulang. Contohnya, mengalikan angka dengan 1 selalu memberi hasil yang sama.
Dalam REST API, artinya sederhana. Klien mengirim request yang sama sekali atau sepuluh kali, dan kondisi akhir di server tetap sama. Respons boleh berbeda, tetapi efek di sisi server tidak boleh bertambah.
Sebagai gambaran, perintah “ubah nama pengguna menjadi Budi” bersifat idempotent. Perintah “tambah saldo Rp10.000” tidak, karena setiap pengulangan menambah saldo lagi.
Mengapa Idempotency Penting dalam REST API?
Jaringan tidak selalu stabil. Klien sering mengirim ulang request karena beberapa alasan:
- koneksi putus sebelum respons sampai,
- timeout terjadi padahal server sudah memproses request,
- pengguna menekan tombol bayar dua kali,
- sistem retry otomatis di klien atau gateway aktif.
Bayangkan klien mengirim request pembayaran. Server memprosesnya dan menarik dana, tetapi respons hilang di jalan. Klien menganggap request gagal lalu mengirim ulang. Hasilnya, pelanggan ditagih dua kali.
Idempotency menutup celah ini. Server mengenali request yang sama dan tidak memprosesnya untuk kedua kalinya.
Metode HTTP yang Bersifat Idempotent
Spesifikasi HTTP sudah mendefinisikan metode mana yang idempotent. Berikut ringkasannya.
| Metode | Idempotent | Safe (tidak mengubah data) |
|---|---|---|
| GET | Ya | Ya |
| HEAD | Ya | Ya |
| OPTIONS | Ya | Ya |
| PUT | Ya | Tidak |
| DELETE | Ya | Tidak |
| POST | Tidak | Tidak |
| PATCH | Tidak dijamin | Tidak |
Perhatikan bahwa POST tidak idempotent secara bawaan. Padahal POST paling sering dipakai untuk membuat transaksi, pesanan, dan pembayaran. Di sinilah idempotency perlu kamu tambahkan sendiri.
DELETE termasuk idempotent karena menghapus data yang sama berulang kali menghasilkan kondisi akhir yang sama, yaitu data sudah hilang. Respons kedua boleh berupa 404, dan itu tidak masalah. Penjelasan resminya ada di dokumentasi MDN tentang idempotent.
Cara Kerja Idempotency Key
Cara paling umum menambahkan idempotency pada POST adalah memakai header Idempotency-Key. Alurnya begini:
- Klien membuat kunci unik, biasanya UUID, untuk setiap operasi.
- Klien mengirim kunci itu lewat header
Idempotency-Key. - Server memeriksa apakah kunci tersebut sudah pernah dipakai.
- Jika belum, server memproses request lalu menyimpan hasilnya bersama kuncinya.
- Jika sudah, server tidak memproses ulang dan mengembalikan respons yang tersimpan.
Dengan begitu, retry sebanyak apa pun hanya menghasilkan satu efek. Pendekatan ini dipopulerkan oleh Stripe, dan kamu bisa melihat penerapannya di dokumentasi idempotent requests Stripe.
Contoh Implementasi Idempotency
Berikut contoh sederhana dengan Node.js dan Express. Contoh ini memakai penyimpanan key-value seperti Redis.
javascript
app.post("/payments", async (req, res) => {
const key = req.header("Idempotency-Key");
if (!key) return res.status(400).json({ error: "Idempotency-Key wajib" });
const bodyHash = hash(req.body);
const locked = await store.setIfAbsent(
key, { bodyHash, state: "processing" }, 86400
);
if (!locked) {
const saved = await store.get(key);
if (saved.bodyHash !== bodyHash)
return res.status(422).json({ error: "Key dipakai untuk data berbeda" });
if (saved.state === "processing")
return res.status(409).json({ error: "Request masih diproses" });
return res.status(saved.status).json(saved.body);
}
const result = await createPayment(req.body);
await store.set(
key, { bodyHash, state: "done", status: 201, body: result }, 86400
);
res.status(201).json(result);
});
Beberapa hal penting dari kode di atas:
setIfAbsentbersifat atomik, sehingga dua request bersamaan tidak lolos sekaligus.- Hash isi request mendeteksi kunci yang dipakai ulang untuk data berbeda.
- Status
409menandakan request dengan kunci yang sama masih berjalan. - Masa simpan 86400 detik (24 jam) membatasi ukuran penyimpanan.
Praktik Terbaik Idempotency
Agar idempotency berjalan andal, perhatikan hal berikut:
- Buat kunci di sisi klien. Gunakan UUID v4 agar tidak bentrok.
- Simpan kunci secara atomik. Pakai
SET NXdi Redis atau unique constraint di database. - Bandingkan isi request. Tolak dengan status 422 jika kunci sama tetapi datanya berbeda.
- Tentukan masa berlaku kunci. Umumnya 24 jam sampai 7 hari, sesuai kebutuhan bisnis.
- Simpan respons asli. Kembalikan status code dan body yang sama saat retry.
- Wajibkan kunci pada operasi sensitif, terutama pembayaran dan pembuatan pesanan.
Untuk acuan standar, baca RFC 9110 tentang semantik HTTP.
Kesalahan Umum saat Menerapkan Idempotency
Banyak developer terjebak pada kesalahan berikut:
- Memeriksa kunci lalu menyimpannya di dua langkah terpisah, sehingga muncul race condition.
- Tidak menghapus kunci saat proses gagal, sehingga klien tidak bisa mencoba lagi.
- Memakai kunci yang bisa ditebak, misalnya ID pengguna saja.
- Menyimpan kunci tanpa batas waktu sehingga penyimpanan membengkak.
Jika proses gagal karena error sementara, hapus atau tandai kunci sebagai gagal agar klien bisa mengulang dengan aman.
Kesimpulan
Idempotency memastikan request yang dikirim ulang tidak menimbulkan efek ganda. Metode seperti GET, PUT, dan DELETE sudah idempotent secara bawaan. POST perlu bantuan Idempotency-Key, penyimpanan atomik, dan pengecekan isi request. Dengan penerapan yang tepat, API kamu tahan terhadap retry, timeout, dan klik ganda dari pengguna.
Sudah pernah menerapkan idempotency di proyekmu? Ceritakan pengalamanmu di kolom komentar.
One Reply to “Mengenal Idempotency dalam REST API: Cara Mencegah Request Diproses Berulang Kali”