Idempotency adalah sifat sebuah operasi yang hasil akhirnya tetap sama, baik dijalankan satu kali maupun berkali-kali. Konsep ini terdengar abstrak, tetapi dampaknya sangat nyata. Bayangkan Anda menekan tombol “Bayar” di aplikasi belanja, lalu layar tidak merespons karena sinyal buruk. Anda menekannya lagi. Beberapa menit kemudian, saldo terpotong dua kali untuk satu pesanan.
Kejadian seperti ini bukan semata-mata salah pengguna. Jaringan memang tidak bisa diandalkan, dan klien sering mengirim ulang permintaan yang tampak gagal. Jika server memperlakukan setiap permintaan ulang sebagai pekerjaan baru, data bisa ganda, uang bisa terpotong dua kali, dan email bisa terkirim berkali-kali.
Artikel ini menjelaskan apa itu idempotency dalam programming, masalah yang muncul tanpanya, lima alasan mengapa konsep ini penting, hubungannya dengan HTTP method, serta contoh kode di JavaScript, Express, dan SQL. Anda juga akan menemukan strategi penerapan, batasan, dan kesalahan umum yang sering terjadi.
Daftar Isi
Apa Itu Idempotency dalam Programming?
Dalam programming, sebuah operasi disebut idempotent jika menjalankannya berkali-kali dengan input yang sama menghasilkan keadaan akhir yang sama dengan menjalankannya sekali. Kata kuncinya adalah keadaan akhir, bukan respons. Respons boleh berbeda, misalnya “berhasil dibuat” pada panggilan pertama dan “sudah ada” pada panggilan berikutnya.
Contoh paling sederhana ada di matematika. Fungsi nilai mutlak memberi hasil yang sama meski dipanggil berulang: abs(abs(-5)) tetap 5. Di dunia program, perintah “atur status pesanan menjadi dibayar” bersifat idempotent, sedangkan perintah “tambah saldo 50.000” tidak. Mengulang perintah pertama tidak mengubah apa-apa, tetapi mengulang perintah kedua menambah saldo lagi.
Analogi yang mudah diingat adalah tombol lift. Menekan tombol lantai 5 sekali atau sepuluh kali menghasilkan hasil yang sama: lift menuju lantai 5. Sebaliknya, mesin kasir yang menambah satu item setiap kali tombol ditekan jelas tidak idempotent.
Masalah pada Sistem Tanpa Idempotency
Mengirim ulang permintaan adalah hal biasa dalam sistem terdistribusi. Ada beberapa situasi yang memicunya:
- Klik ganda. Pengguna menekan tombol dua kali karena halaman terasa lambat.
- Timeout dan retry otomatis. Klien tidak menerima respons, lalu mengulang permintaan padahal server sebenarnya sudah memprosesnya.
- Webhook yang dikirim ulang. Layanan pihak ketiga mengirim notifikasi lagi jika server Anda tidak membalas tepat waktu.
- Antrean pesan. Banyak message queue menjamin pesan terkirim minimal satu kali, sehingga pesan yang sama bisa diterima dua kali.
- Pengguna menyegarkan halaman. Formulir terkirim ulang saat halaman dimuat ulang.
Tanpa perlindungan, setiap pengulangan itu menimbulkan efek ganda: pesanan duplikat, transaksi ganda, stok berkurang dua kali, atau notifikasi berulang. Masalahnya sulit dilacak karena kodenya tidak salah. Struktur operasinya yang tidak aman diulang.
5 Alasan Idempotency Penting dalam Programming
1. Idempotency Mencegah Efek Ganda
Ini alasan paling mendasar. Dengan operasi yang aman diulang, pembayaran tidak terpotong dua kali dan data tidak tersimpan ganda. Pengguna pun tidak perlu takut menekan tombol ulang.
2. Retry Menjadi Aman
Menurut spesifikasi HTTP, metode yang bersifat idempotent boleh diulang otomatis jika koneksi putus sebelum klien membaca respons. Klien tahu bahwa mengulang permintaan memberi efek yang sama, meski permintaan pertama ternyata sudah berhasil. Hal ini memungkinkan mekanisme retry dibuat tanpa takut merusak data.
3. Sistem Lebih Tahan terhadap Kegagalan Jaringan
Dalam sistem terdistribusi, kegagalan sebagian adalah hal wajar. Dengan operasi yang aman diulang, sistem bisa pulih dari timeout dan pemutusan koneksi tanpa campur tangan manusia. Ini menurunkan jumlah insiden yang harus dibereskan manual.
4. Pemrosesan Pesan dan Webhook Lebih Andal
Antrean dan webhook umumnya memberi jaminan “minimal satu kali”. Artinya, konsumen harus siap menerima pesan yang sama lebih dari sekali. Dengan menyimpan ID pesan yang sudah diproses, konsumen cukup mengabaikan duplikat.
5. Debugging dan Operasional Lebih Mudah
Ketika operasi aman diulang, tim bisa menjalankan ulang pekerjaan yang gagal tanpa khawatir menimbulkan efek samping baru. Skrip migrasi, tugas terjadwal, dan proses sinkronisasi menjadi lebih mudah dipulihkan setelah gagal di tengah jalan.

Idempotency pada HTTP Method
HTTP sudah mengatur sifat ini sejak lama. Dalam RFC 9110 tentang semantik HTTP, sebuah metode dianggap idempotent jika efek yang diinginkan pada server dari beberapa permintaan identik sama dengan efek dari satu permintaan. Metode PUT, DELETE, dan semua metode yang aman termasuk idempotent.
Dua istilah sering tertukar, yaitu aman (safe) dan idempotent. Metode aman, seperti GET, tidak mengubah data di server. Metode idempotent boleh mengubah data, asalkan mengulangnya tidak mengubah hasil akhir. Semua metode aman otomatis idempotent, tetapi tidak sebaliknya.
| Metode | Aman (safe) | Idempotent | Keterangan |
|---|---|---|---|
| GET | Ya | Ya | Hanya membaca data |
| HEAD, OPTIONS | Ya | Ya | Meminta metadata atau opsi |
| PUT | Tidak | Ya | Mengganti resource dengan data lengkap |
| DELETE | Tidak | Ya | Resource tetap terhapus meski diulang |
| POST | Tidak | Tidak | Biasanya membuat resource baru |
| PATCH | Tidak | Tidak | Bergantung pada isi perubahan |
Perhatikan bahwa DELETE tetap idempotent walaupun respons kedua bisa berbeda, misalnya 404 karena data sudah terhapus. Yang dihitung adalah keadaan akhir di server, yaitu data tidak ada lagi. Sebaliknya, POST yang membuat pesanan baru tidak idempotent secara bawaan, karena setiap pengulangan menciptakan pesanan lain. Jika Anda sedang merancang API, pertimbangan ini juga relevan dengan pembahasan di REST API vs GraphQL: Mana yang Lebih Cocok untuk Proyek Web Modern?.
Contoh Kode Idempotency
Mulai dari perbedaan paling dasar. Fungsi pertama menambah nilai, sehingga setiap panggilan mengubah hasil. Fungsi kedua menetapkan nilai, sehingga hasil akhirnya sama berapa kali pun dipanggil.
// Tidak idempotent: setiap panggilan mengubah hasil akhir
function tambahStok(produk, jumlah) {
produk.stok += jumlah;
}
// Idempotent: hasil akhir sama berapa kali pun dipanggil
function aturStok(produk, jumlah) {
produk.stok = jumlah;
}
Hal serupa berlaku di SQL. Perintah pertama mengurangi saldo setiap kali dijalankan. Perintah kedua hanya menetapkan status, sehingga aman diulang. Perintah ketiga memakai upsert, dan membutuhkan constraint unik pada kolom id_pengguna.
-- Tidak idempotent: saldo berkurang setiap kali dijalankan
UPDATE dompet SET saldo = saldo - 50000 WHERE id_pengguna = 7;
-- Idempotent: status akhir selalu 'dibayar'
UPDATE pesanan SET status = 'dibayar' WHERE id_pesanan = 1001;
-- Idempotent: sisipkan jika belum ada, perbarui jika sudah ada
INSERT INTO langganan (id_pengguna, paket)
VALUES (7, 'pro')
ON CONFLICT (id_pengguna) DO UPDATE SET paket = EXCLUDED.paket;
Lalu bagaimana dengan operasi yang secara alami tidak idempotent, seperti membuat pembayaran lewat POST? Solusinya adalah idempotency key. Klien mengirim kunci unik pada header, dan server menyimpan kunci itu beserta hasilnya. Jika kunci yang sama datang lagi, server mengembalikan hasil yang tersimpan tanpa memprosesnya ulang. Pertama, buat tabel untuk menyimpan kunci.
CREATE TABLE idempotency_keys (
kunci TEXT PRIMARY KEY,
status_http INT,
respons JSONB,
dibuat_pada TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Kedua, handler Express berikut menyisipkan kunci di dalam transaksi yang sama dengan pemrosesan. Jika dua permintaan dengan kunci identik datang bersamaan, permintaan kedua menunggu sampai yang pertama selesai, lalu menerima hasil yang tersimpan.
app.post('/pembayaran', async (req, res) => {
const kunci = req.get('Idempotency-Key');
if (!kunci) {
return res.status(400).json({ error: 'Header Idempotency-Key wajib diisi' });
}
const klien = await pool.connect();
try {
await klien.query('BEGIN');
const sisip = await klien.query(
`INSERT INTO idempotency_keys (kunci) VALUES ($1)
ON CONFLICT (kunci) DO NOTHING RETURNING kunci`,
[kunci]
);
if (sisip.rowCount === 0) {
// Kunci sudah pernah dipakai: kembalikan hasil yang tersimpan
await klien.query('ROLLBACK');
const { rows } = await pool.query(
'SELECT status_http, respons FROM idempotency_keys WHERE kunci = $1',
[kunci]
);
return res.status(rows[0].status_http).json(rows[0].respons);
}
const hasil = await prosesPembayaran(req.body, klien);
await klien.query(
'UPDATE idempotency_keys SET status_http = 201, respons = $2 WHERE kunci = $1',
[kunci, hasil]
);
await klien.query('COMMIT');
res.status(201).json(hasil);
} catch (err) {
await klien.query('ROLLBACK');
res.status(500).json({ error: 'Gagal memproses pembayaran' });
} finally {
klien.release();
}
});
Kode ini sengaja disederhanakan. Pada produksi, Anda perlu memeriksa bahwa isi permintaan sama untuk kunci yang sama, menangani kunci kedaluwarsa, dan meneruskan kunci ke layanan pembayaran eksternal agar efek di luar database juga terlindungi. Jika klien dan server berada di domain berbeda, pastikan header Idempotency-Key diizinkan oleh konfigurasi CORS. Penyebab dan solusinya dibahas di CORS Error: Penyebab dan 5 Cara Mengatasinya di Express.

Strategi Menerapkan Idempotency
Tidak ada satu teknik yang cocok untuk semua kasus. Pilih berdasarkan jenis operasinya:
- Rancang operasi sebagai penetapan, bukan penambahan. “Atur status menjadi dibayar” lebih aman daripada “tambah satu”. Jika memungkinkan, ubah desain operasi agar bersifat idempotent secara alami.
- Gunakan idempotency key untuk operasi pembuatan. Klien membuat kunci unik, misalnya UUID, dan mengirimnya di setiap percobaan ulang untuk permintaan yang sama.
- Pasang constraint unik di database. Kunci primer atau unique constraint mencegah baris ganda walaupun kode aplikasi gagal mencegahnya. Dasar pemilihan kunci dibahas di Mengapa Database Normalization Penting dalam Perancangan Sistem?.
- Simpan ID pesan yang sudah diproses. Untuk webhook dan antrean, catat ID event dan abaikan yang sudah pernah diproses.
- Periksa status sebelum bertindak. Misalnya, hanya proses pesanan yang masih berstatus “menunggu pembayaran”.
- Gunakan upsert. Perintah seperti
INSERT ... ON CONFLICTmenggabungkan pembuatan dan pembaruan dalam satu langkah yang aman diulang. - Terapkan retry dengan jeda bertahap. Retry aman hanya jika operasinya idempotent, dan jeda yang bertambah mencegah server kebanjiran permintaan ulang.
Batasan Idempotency yang Perlu Dipahami
Konsep ini sangat berguna, tetapi bukan jaminan mutlak. Ada beberapa hal yang perlu Anda waspadai:
- Efek di luar sistem. Mengirim email atau memanggil layanan eksternal tidak ikut dibatalkan oleh transaksi database. Kunci perlu diteruskan atau efek itu perlu dicatat terpisah.
- Kunci yang dipakai ulang dengan isi berbeda. Jika kunci sama datang dengan data lain, kembalikan error yang jelas, jangan diam-diam memakai hasil lama.
- Masa berlaku kunci. Menyimpan kunci selamanya memakan ruang. Tentukan masa berlaku yang sesuai dengan kebutuhan retry klien.
- Permintaan bersamaan. Dua permintaan dengan kunci sama bisa tiba pada waktu hampir bersamaan, sehingga perlu penguncian atau transaksi.
- Respons tidak harus identik. Yang dijaga adalah keadaan akhir, jadi respons boleh sedikit berbeda, misalnya status 200 menggantikan 201.
Kesalahan Umum dalam Menerapkan Idempotency
- Menganggap semua PUT otomatis aman. Spesifikasi hanya menyatakan maksudnya idempotent. Jika kode Anda menambah nilai saat menerima PUT, sifat itu hilang.
- Memakai GET untuk mengubah data. Pengaman seperti cache dan prefetch bisa memicu perubahan tanpa disengaja.
- Memeriksa lalu menyisipkan tanpa constraint. Dua permintaan bersamaan bisa sama-sama lolos pemeriksaan, sehingga data ganda tetap lahir.
- Membuat kunci baru di setiap retry. Klien harus memakai kunci yang sama untuk percobaan ulang pada permintaan yang sama.
- Mengabaikan efek samping. Email, notifikasi, dan panggilan API pihak ketiga ikut menjadi duplikat jika tidak dilindungi.
- Tidak menguji pengulangan. Tulis tes yang mengirim permintaan yang sama dua atau tiga kali dan pastikan hasil akhirnya satu.
Pertanyaan yang Sering Diajukan tentang Idempotency
Apa bedanya idempotent dan safe?
Metode aman tidak mengubah data di server, misalnya GET. Metode idempotent boleh mengubah data, tetapi mengulangnya tidak mengubah hasil akhir, misalnya PUT dan DELETE. Semua metode aman otomatis idempotent, tetapi tidak semua metode idempotent aman.
Apakah POST bisa dibuat idempotent?
Bisa. Gunakan idempotency key pada header, simpan hasilnya, dan kembalikan hasil yang sama jika kunci yang sama datang lagi. Banyak API pembayaran memakai pola ini.
Apakah idempotent berarti respons selalu sama?
Tidak. Yang dijaga adalah keadaan akhir di server. Respons kedua pada DELETE bisa berupa 404, tetapi data tetap sudah terhapus, sehingga operasinya tetap idempotent.
Apakah idempotency hanya untuk API?
Tidak. Konsep ini berlaku pada skrip migrasi, tugas terjadwal, konsumen antrean, dan konfigurasi infrastruktur. Di mana pun sebuah pekerjaan mungkin dijalankan lebih dari sekali, sifat ini berguna.
Daftar Periksa Operasi yang Aman Diulang
- Apakah operasi ini bisa dijalankan dua kali tanpa efek ganda?
- Apakah operasi dirancang sebagai penetapan, bukan penambahan?
- Apakah operasi pembuatan memakai idempotency key?
- Apakah ada constraint unik di database sebagai pengaman terakhir?
- Apakah webhook dan pesan antrean dicek berdasarkan ID yang sudah diproses?
- Apakah efek samping seperti email dan panggilan eksternal sudah dilindungi?
- Apakah masa berlaku kunci dan kasus kunci bentrok sudah ditentukan?
- Apakah ada tes yang mengirim permintaan sama berulang kali?
Kesimpulan: Idempotency Membuat Sistem Aman Diulang dan Lebih Andal
Idempotency membuat sebuah operasi aman dijalankan berkali-kali karena hasil akhirnya tetap sama. Dengan sifat ini, klik ganda, retry otomatis, webhook ganda, dan pesan antrean yang terkirim ulang tidak lagi merusak data. Hasilnya, sistem lebih tahan terhadap kegagalan jaringan dan lebih mudah dipulihkan.
Mulailah dari hal sederhana: rancang operasi sebagai penetapan, pasang constraint unik, dan gunakan idempotency key untuk operasi pembuatan seperti pembayaran. Lalu uji dengan mengirim permintaan yang sama berulang kali. Dengan begitu, aplikasi Anda tetap benar walaupun jaringan tidak bersahabat.
Artikel Lainnya di NgodingDaily
Lanjutkan belajar dengan topik lain yang saling melengkapi:
- REST API vs GraphQL: Mana yang Lebih Cocok untuk Proyek Web Modern?
- Mengapa Database Normalization Penting dalam Perancangan Sistem?
- CORS Error: Penyebab dan 5 Cara Mengatasinya di Express
- JWT vs Session: 5 Perbedaan dan Mana yang Harus Dipakai
- Server-Side Rendering vs Client-Side Rendering: 5 Perbedaan dan Mana yang Harus Dipilih