Untuk menjaga konsistensi data ketika consumer mengirim ulang request akibat timeout atau retry otomatis, kontrak API harus menjamin idempotensi. Artikel ini menjelaskan bagaimana menyusun kontrak API dan webhook terdistribusi agar tetap aman saat retry, meliputi pola deduplikasi, storage state, versi schema, penanganan partial auth failure, observabilitas, dan strategi testing bersama consumer.
1. Merancang Kontrak API yang Idempoten
Idempotensi tidak hanya soal HTTP method, tapi juga mekanisme kontrak. Kontrak harus menyertakan komponen yang memungkinkan server mengenali duplikat request. Salah satu pendekatan yang paling kuat adalah meminta client menyertakan idempotency key yang unik per intent bisnis. Kontrak juga menegaskan bahwa key tersebut harus tetap sama jika client hendak retry karena timeout, dan API harus menolak permintaan baru dengan key yang sama jika sudah diproses.
Selain itu, kontrak sebaiknya menjelaskan level idempotensi: apakah hanya operasi pendaftaran data (create resource) atau juga update bersyarat. Sediakan dokumentasi urutan status yang mungkin kembali dari server sehingga client tahu kapan boleh retry.
2. Pola Deduplikasi dan Validasi Payload
2.1 Idempotency Token
Token ini disisipkan dalam header atau payload. Server mencatat token beserta hasilnya dan menolak permintaan baru dengan token sama apabila status sudah final (success atau failure yang tidak dapat di-retry). Implementasi sederhana bisa seperti ini:
// Pseudocode storage check
function handleRequest(request) {
token = request.headers['X-Idempotency-Key']
if (!token) throw new Error('Idempotency key required')
record = storage.find(token)
if (record) return record.response
response = processBusinessLogic(request.body)
storage.save(token, {request, response, status: 'completed'})
return response
}
Catatan: storage tidak boleh hanya mencatat token, tapi juga status (processing, completed). Status processing membantu mendeteksi retry saat request sebelumnya masih berjalan.
2.2 Payload Hash dan Sequence Number
Jika client tidak bisa menjamin token unik, kontrak dapat menetapkan field hash atau sequence number. Server membandingkan payload hash untuk memastikan retry memiliki isi yang konsisten, sehingga perubahan tidak sengaja dikenali sebagai request berbeda.
Sequence number berguna untuk webhook terdistribusi yang mengirim event berurutan. Kontrak harus menjelaskan jika server menerima event dengan sequence lebih tinggi maka menyimpan sementara, atau jika sequence lebih rendah maka dianggap duplikat.
3. Penyimpanan Status di Server
State deduplikasi harus tahan banting dan cepat diakses. Pilihan umum:
- Database transaksional: simpan token + request checksum + status. Gunakan constraint unik pada token untuk mencegah double commit.
- Cache terdistribusi (Redis, memcached): untuk throughput tinggi, simpan token dengan TTL yang mencerminkan window retry. Pastikan persistenasi jika dibutuhkan audit.
Kontrak API perlu menjelaskan berapa lama server menyimpan state tersebut dan bagaimana client dapat menanyakan status jika tidak yakin apakah request diproses.
4. Strategi Versioning Schema
Jika kontrak berubah — misalnya menambahkan header idempotency atau payload baru — versi schema harus bertahan tanpa memecah client lama. Beberapa strategi:
- Versioned endpoint: /v1/orders/intake tetap digunakan hingga semua consumer migrasi.
- Schema negotiation: client mengirim header Accept-Version, server mencatat kemampuan deduplikasi berbeda.
Kontrak harus mendokumentasikan bagaimana perubahan memengaruhi idempotensi. Contoh: jika field baru memperkenalkan kondisi retry, versi baru harus menjelaskan perilaku deduplikasi yang berbeda untuk field tersebut.
5. Penanganan Partial Auth Failure
Retry karena refresh token atau scope hilang adalah kasus umum. Kontrak API harus menjelaskan:
- Jika auth gagal karena token kadaluarsa, client dapat refresh lalu retry dengan idempotency key sama.
- Jika scope hilang, server mengembalikan 403 dengan pesan spesifik agar client tidak otomatis retry.
Server tidak boleh menganggap retry sebagai duplikat sebelum memastikan permintaan sebelumnya berhasil. Oleh karena itu, status processing sangat membantu untuk memutuskan apakah retry boleh diteruskan setelah auth diperbarui.
6. Observabilitas untuk Mendeteksi Retry Berulang
Untuk memastikan kontrak idempoten berfungsi, siapkan observabilitas:
- Log struktur: log harus mencatat token idempotensi, status, dan waktu. Contoh log: "idempotency=abc123 status=processing duration=120ms".
- Tracing: tambahkan span untuk deduplikasi dan proses bisnis. Jika retry terjadi, tracing menunjukkan apakah request baru memicu logic atau langsung menjawab dari cache.
- Metric retry: hitung jumlah request yang ditolak karena token duplikat dan bandingkan dengan jumlah request baru.
Gunakan dashboard sederhana untuk memantau pola retry tinggi; sering kali menandakan timeout terlalu pendek atau masalah jaringan.
7. Testing Kontrak dengan Consumer
Uji bersama consumer penting untuk memastikan tidak ada efek samping:
- Simulasikan retry dengan idempotency key sama sambil memantau state di server.
- Uji skenario partial auth failure: kirim request dengan refresh token yang kadaluarsa lalu retry setelah token baru diperoleh.
- Verifikasi observability: pastikan log/tracing merefl ekan deduplikasi dan tidak ada request ganda yang mencapai proses bisnis.
Dokumentasikan langkah-langkah testing ini dalam kontrak agar consumer tahu cara mengecek compliance sebelum roll-out.
Kesimpulan
Menjamin idempotensi kontrak API saat retry dan webhook terdistribusi membutuhkan kombinasi pola deduplikasi, state server yang dapat diandalkan, versi schema yang jelas, penanganan auth yang tepat, observabilitas, dan testing bersama consumer. Kontrak yang eksplisit membantu developer menghadapi retry otomatis tanpa memunculkan efek samping. Terapkan pendekatan yang disepakati agar semua pihak memahami kapan dan bagaimana retry boleh terjadi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!