API versioning tanpa merusak integrasi berarti perubahan pada API dilakukan dengan menjaga kontrak yang sudah dipakai klien tetap dapat bekerja, setidaknya selama masa transisi yang jelas. Masalah utamanya bukan sekadar menambah angka versi, tetapi mengelola API contract, kompatibilitas mundur, observabilitas adopsi, dan rencana penghentian yang bisa diprediksi.
Jika tim Anda memiliki klien mobile lama, partner eksternal, atau beberapa frontend yang tidak bisa di-upgrade serentak, pendekatan versioning yang buruk akan memicu error di produksi. Solusi yang lebih aman adalah membedakan additive change dan breaking change, menjaga error contract tetap stabil, memakai version di path atau header sesuai kebutuhan, lalu mengumumkan deprecation dan sunset secara eksplisit.
Apa yang Sebenarnya Di-version?
Kesalahan umum adalah menganggap versi hanya menempel pada URL seperti /v1 atau /v2. Dalam praktiknya, yang perlu dikelola adalah kontrak API: bentuk request, bentuk response, arti field, aturan validasi, status code, dan format error.
Sebuah endpoint bisa tetap berada di URL yang sama, tetapi kontraknya berubah secara breaking. Sebaliknya, Anda juga bisa menambah field baru tanpa perlu mengganti versi jika perubahan itu kompatibel terhadap klien lama.
Komponen kontrak yang harus dianggap stabil
- Nama field pada request dan response
- Tipe data, misalnya string menjadi object adalah perubahan besar
- Semantik field, misalnya
status=paidyang artinya berubah - Required vs optional pada input
- Shape error response dan kode error internal
- Status code HTTP yang diharapkan klien
Aturan praktis: kalau perubahan membuat klien lama perlu diubah agar tetap berjalan, anggap itu breaking change.
Additive Change vs Breaking Change
Perubahan yang biasanya aman
Perubahan berikut umumnya kompatibel mundur jika klien ditulis dengan baik:
- Menambah field baru pada response
- Menambah endpoint baru
- Menambah nilai enum jika klien tidak mengasumsikan daftar nilai tertutup tanpa fallback
- Menambah field optional pada request
- Menambah metadata non-kritis
Contoh response yang berubah secara additive:
{
"id": "ord_123",
"status": "paid",
"total": 150000,
"currency": "IDR"
}Menjadi:
{
"id": "ord_123",
"status": "paid",
"total": 150000,
"currency": "IDR",
"paid_at": "2026-04-10T08:30:00Z"
}Jika klien mengabaikan field yang tidak dikenal, perubahan ini aman.
Perubahan yang tergolong breaking
- Menghapus field yang masih dipakai klien
- Mengganti nama field
- Mengubah tipe data field
- Mengubah field optional menjadi required
- Mengubah struktur nested object
- Mengubah arti bisnis dari nilai yang sama
- Mengganti format error yang di-parse klien
Contoh breaking:
{
"customer_name": "Budi"
}Diubah menjadi:
{
"customer": {
"name": "Budi"
}
}Walau data yang dibawa sama, bentuk kontraknya berubah dan parser klien lama bisa gagal.
Kapan Memakai Version di Path, Kapan di Header?
Tidak ada satu pendekatan yang selalu benar. Pilihan terbaik bergantung pada siapa konsumennya, seberapa besar perubahan, dan bagaimana infrastruktur Anda menangani routing, cache, logging, serta dokumentasi.
Version di path
GET /api/v1/orders/ord_123
GET /api/v2/orders/ord_123Cocok saat:
- Partner eksternal butuh kontrak yang sangat eksplisit
- Tim operasional ingin mudah memisahkan traffic per versi
- Dokumentasi per versi perlu jelas dan mudah dicari
- Perubahan antarversi cukup besar
Kelebihan:
- Sangat mudah dipahami
- Mudah dirouting, dimonitor, dan diuji
- Lebih sederhana untuk gateway, CDN, dan access log
Kekurangan:
- Mudah menggandakan endpoint dan logika bisnis
- Tim cenderung membuat versi baru terlalu cepat
- Refactor lintas versi bisa menjadi mahal
Version di header
Contoh umum:
Accept: application/vnd.example+json; version=2Atau header kustom:
API-Version: 2Cocok saat:
- URL ingin tetap stabil
- Perubahan kontrak lebih halus dan endpoint tetap sama
- Anda punya disiplin dokumentasi dan observabilitas yang baik
Kelebihan:
- URL tidak berubah
- Lebih fleksibel untuk evolusi representasi resource
- Berguna jika satu resource punya beberapa representasi
Kekurangan:
- Lebih sulit dilihat dari log sederhana atau browser
- Perlu perhatian pada cache dan vary header
- Sering membingungkan jika tim belum konsisten
Panduan memilih
- Pakai path jika Anda melayani banyak partner eksternal dan ingin batas versi yang eksplisit.
- Pakai header jika Anda ingin URL tetap stabil dan perubahan lebih banyak pada representasi data daripada resource.
- Jangan campur tanpa aturan. Jika sebagian endpoint memakai path dan sebagian header, dokumentasikan alasan dan pola migrasinya.
Untuk banyak tim backend, strategi yang pragmatis adalah: gunakan path versioning untuk perubahan besar lintas partner, dan gunakan evolusi schema yang kompatibel untuk perubahan kecil tanpa menambah versi mayor.
Evolusi Schema Request/Response yang Aman
Prinsip response: longgar dalam menerima perubahan
Server sebaiknya bisa menambah field baru tanpa merusak klien. Agar ini berhasil, klien perlu dibuat untuk mengabaikan field yang tidak dikenali dan tidak mengasumsikan urutan field JSON.
Prinsip request: konservatif saat menerima input
Perubahan pada request lebih sensitif dibanding response. Menambah field optional biasanya aman, tetapi menambah field required adalah breaking. Karena itu, jika ingin memperkenalkan perilaku baru, lebih aman memakai:
- Field optional baru dengan default yang jelas
- Endpoint baru untuk alur baru yang berbeda signifikan
- Header fitur atau parameter opt-in jika benar-benar diperlukan
Contoh request aman:
{
"amount": 150000,
"currency": "IDR",
"note": "optional"
}Jangan mengubahnya menjadi wajib tanpa masa transisi yang jelas.
Jangan cepat mengganti tipe data
Mengubah total dari number menjadi string agar mendukung format baru terdengar kecil, tetapi ini breaking. Jika harus berubah, lebih aman menambah field baru:
{
"total": 150000,
"total_display": "150000.00"
}Enum adalah jebakan yang sering diabaikan
Menambah nilai enum baru di server bisa merusak klien yang memakai switch tanpa default. Misalnya klien hanya mengenal pending, paid, dan failed, lalu server menambah refunded. Secara teori ini additive, tetapi secara praktik bisa memicu UI kosong atau crash. Karena itu:
- Dokumentasikan enum sebagai daftar yang bisa bertambah
- Siapkan fallback
unknowndi klien - Uji integrasi dengan nilai yang belum dikenal
Deprecate Field dengan Aman
Menghapus field secara langsung adalah penyebab umum integrasi putus. Proses yang lebih aman adalah deprecate lalu sunset.
Pola deprecation field
- Tandai field lama sebagai deprecated di dokumentasi
- Tambahkan field pengganti tanpa menghapus field lama
- Isi keduanya selama masa transisi
- Ukur siapa yang masih memakai field lama
- Komunikasikan tanggal penghentian
- Hapus setelah adopsi cukup dan masa sunset lewat
Contoh transisi:
{
"customer_name": "Budi",
"customer": {
"name": "Budi"
}
}Dalam fase transisi, kedua field tersedia. Setelah mayoritas klien pindah, customer_name bisa dihentikan sesuai kebijakan sunset.
Tambahkan sinyal deprecation di response
Selain dokumentasi, server dapat mengirim header untuk memberi tahu klien dan operator bahwa kontrak lama akan dihentikan. Header yang sering dipakai:
- Deprecation: menandakan resource atau perilaku ini sudah deprecated
- Sunset: memberi tanggal kapan versi atau perilaku akan dihentikan
Contoh:
Deprecation: true
Sunset: Wed, 31 Jul 2026 23:59:59 GMT
Link: <https://api.example.com/docs/migrations/orders-v2>; rel="deprecation"Praktiknya, header ini paling berguna jika disertai tautan migrasi yang jelas: apa yang berubah, siapa terdampak, dan contoh request/response baru.
Jangan gunakan header deprecation sebagai satu-satunya mekanisme komunikasi. Partner eksternal dan tim mobile tetap perlu changelog, email, dashboard, atau notifikasi kontrak yang terstruktur.
Jaga Error Contract Tetap Stabil
Banyak tim fokus pada schema sukses, tetapi lupa bahwa klien sering bergantung pada format error untuk menampilkan pesan, retry, atau membedakan masalah validasi vs otorisasi. Error contract yang berubah diam-diam bisa sama merusaknya dengan perubahan pada response sukses.
Contoh error contract yang konsisten
{
"error": {
"code": "validation_error",
"message": "Input tidak valid",
"details": [
{
"field": "amount",
"reason": "must_be_positive"
}
],
"request_id": "req_7f2a"
}
}Yang penting dijaga stabil:
error.codeuntuk logika aplikasimessageuntuk informasi manusia, bukan basis parsing utamadetailsuntuk validasi yang lebih spesifikrequest_idagar debugging lintas sistem mudah
Hindari klien bergantung pada teks bebas seperti message. Jika perlu perilaku khusus, pakai error.code yang terdokumentasi dan stabil.
Skenario Nyata: Mobile Lama, Partner Eksternal, dan Rollout Bertahap
1. Klien mobile lama yang tidak cepat ter-upgrade
Aplikasi mobile sering tertahan di versi lama selama berminggu-minggu atau berbulan-bulan. Karena itu, breaking change pada endpoint yang sama sangat berisiko. Pendekatan aman:
- Pertahankan kontrak lama selama jendela dukungan tertentu
- Tambahkan field baru secara additive
- Jika perlu perubahan besar, sediakan versi baru terpisah
- Log versi aplikasi dan versi API pada setiap request
Jika aplikasi mobile lama masih mengirim request tanpa field baru, server harus tetap bisa memproses dengan default yang masuk akal.
2. Integrasi partner eksternal
Partner biasanya butuh kontrak yang sangat stabil karena proses perubahan mereka lambat dan sering melibatkan approval non-teknis. Untuk kasus ini, path versioning sering lebih mudah dikelola:
/api/v1/invoices
/api/v2/invoicesKeuntungannya, partner bisa migrasi terjadwal tanpa terpengaruh perubahan representasi default. Sediakan juga dokumen perbandingan versi:
- field yang ditambah
- field yang deprecated
- field yang dihapus
- perubahan validasi
- contoh error baru
3. Rollout bertahap di backend
Tidak semua perubahan harus langsung aktif untuk semua klien. Anda bisa melakukan rollout bertahap dengan:
- Canary untuk sebagian traffic
- Allowlist untuk partner tertentu
- Feature flag di level representasi response
- Header opt-in untuk mencoba kontrak baru sebelum menjadi default
Contoh pendekatan opt-in:
GET /api/orders/ord_123
API-Version: 2Dengan ini, klien yang siap dapat mencoba versi baru tanpa memaksa seluruh ekosistem berubah serentak.
Observabilitas Adopsi Versi dan Deteksi Risiko
Versioning yang aman membutuhkan data, bukan asumsi. Anda perlu tahu siapa yang masih memakai versi lama, field deprecated mana yang masih dibaca, dan endpoint mana yang paling berisiko saat sunset mendekat.
Apa yang perlu dicatat
- Versi API dari path atau header
- Versi aplikasi klien jika tersedia
- Client ID atau partner ID
- Endpoint dan status code
- Header deprecation yang terkirim
- Pemakaian field deprecated, jika bisa dideteksi
- Error rate per versi
Metode observabilitas yang berguna
- Dashboard traffic per versi
- Alert jika versi lama masih dipakai mendekati tanggal sunset
- Log terstruktur dengan
request_id,client_id, danapi_version - Metrik adopsi versi baru dari waktu ke waktu
Untuk field di response, mendeteksi apakah klien benar-benar memakainya memang tidak mudah. Karena itu, biasanya observabilitas terbaik datang dari kombinasi telemetry klien, kontrak partner, dan periode transisi yang cukup panjang.
Fallback Saat Klien Belum Pindah
Idealnya semua klien migrasi tepat waktu, tetapi kenyataannya sering tidak. Karena itu perlu strategi fallback yang realistis.
Pilihan fallback yang umum
- Perpanjang masa sunset untuk klien kritis yang belum siap
- Berikan compatibility layer yang memetakan kontrak baru ke bentuk lama
- Isolasi partner tertentu pada versi lama untuk jangka waktu terbatas
- Turunkan perubahan menjadi additive jika ternyata breaking change belum benar-benar diperlukan
Namun fallback juga punya biaya: kode lebih kompleks, pengujian lebih mahal, dan risiko perilaku berbeda antarversi. Karena itu, fallback harus punya batas waktu dan owner yang jelas.
Compatibility layer sederhana
Misalnya layanan internal Anda sudah memakai schema baru, tetapi partner lama masih membutuhkan field lama. Gateway atau adapter dapat membentuk response lama tanpa memaksa domain model inti tetap kotor oleh warisan kontrak.
Pendekatan ini berguna, tetapi hati-hati agar tidak berubah menjadi lapisan permanen yang tidak pernah dibersihkan.
Checklist Migrasi API Versioning Tanpa Merusak Integrasi
- Identifikasi apakah perubahan termasuk additive atau breaking
- Tentukan apakah cukup evolusi schema atau perlu versi baru
- Bekukan kontrak error agar tetap konsisten
- Tambahkan field baru sebelum menghapus field lama
- Tandai deprecation di dokumentasi dan response header
- Tetapkan tanggal sunset yang realistis
- Siapkan panduan migrasi dengan contoh request/response
- Instrumentasi traffic per versi, client ID, dan error rate
- Lakukan rollout bertahap dan monitor anomali
- Hubungi klien yang belum bermigrasi menjelang sunset
- Hapus kontrak lama hanya setelah bukti adopsi cukup
Dokumentasi dan Changelog yang Benar-Benar Berguna
Dokumentasi versioning yang baik bukan sekadar daftar endpoint. Fokusnya harus pada apa yang berubah, siapa yang terdampak, dan apa tindakan yang harus dilakukan klien.
Isi changelog yang sebaiknya selalu ada
- Tanggal rilis
- Jenis perubahan: additive, deprecated, breaking
- Endpoint yang terdampak
- Contoh sebelum dan sesudah
- Tanggal deprecation dan sunset
- Langkah migrasi yang wajib
- Kontak atau kanal support untuk partner
Contoh format ringkas:
2026-04-10
- Added: field `customer.name` pada GET /orders/{id}
- Deprecated: field `customer_name`
- Sunset: `customer_name` akan dihapus setelah 2026-07-31
- Migration: gunakan `customer.name` sebagai penggantiPraktik yang Bisa Langsung Diterapkan Tim Backend
- Anggap schema request, response, dan error sebagai kontrak publik
- Default ke perubahan additive, bukan breaking
- Gunakan path versioning untuk batas versi yang tegas pada partner eksternal
- Gunakan header versioning jika URL perlu stabil dan tim siap mengelola observabilitasnya
- Jangan hapus field lama tanpa fase deprecation dan sunset
- Kirim header
DeprecationdanSunsetuntuk memberi sinyal transisi - Sertakan link dokumentasi migrasi pada response atau portal developer
- Pastikan format error stabil dan bisa diandalkan klien
- Ukur traffic per versi sebelum mematikan versi lama
- Siapkan fallback sementara, tetapi beri batas waktu penghapusan
Penutup
API versioning tanpa merusak integrasi bukan soal memilih path atau header semata, melainkan disiplin menjaga kontrak tetap stabil saat sistem berkembang. Jika tim membedakan additive dan breaking change dengan jelas, mendeprecate field secara bertahap, menjaga error contract tetap konsisten, dan mengumumkan sunset dengan data adopsi yang memadai, migrasi API akan jauh lebih aman bagi klien mobile, partner eksternal, dan layanan internal.
Mulailah dari hal yang paling praktis: audit kontrak API yang sudah ada, definisikan kebijakan deprecation, tambahkan observabilitas versi, lalu pastikan setiap perubahan schema melewati pertanyaan sederhana: apakah klien lama masih bisa berjalan tanpa perubahan?
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!