Menjaga Kompatibilitas Frontend dengan API yang Digunakannya

Kamu punya build frontend baru yang siap. Tim sudah meninjau perubahan, pengujian lulus, dan bundle sudah berada di CDN menunggu untuk di-deploy. Namun sebelum kamu menekan tombol, ada satu pertanyaan yang sering terlewatkan: akankah frontend ini masih berfungsi dengan API yang sudah berjalan di production?

Frontend dan backend jarang dirilis bersamaan. API mungkin masih melayani versi lama sementara frontend kamu mengharapkan endpoint baru. Atau tim API baru saja melakukan deploy perubahan yang memutuskan kompatibilitas, dan frontend kamu dibangun sebelum perubahan itu terjadi. Bagaimanapun, pengguna akhirnya melihat halaman rusak, data hilang, atau error diam-diam yang tidak ada yang sadari sampai seseorang mengeluh.

Ini bukan masalah alat. Ini adalah masalah koordinasi yang muncul di pipeline kamu.

Mengapa Frontend dan API Bisa Tidak Sinkron

Frontend dan backend memiliki ritme rilis yang berbeda secara fundamental. Frontend statis yang diletakkan di CDN bisa di-deploy secara instan. Tidak perlu restart server, tidak perlu connection drain, tidak perlu migrasi. Kamu push file, dan request pengguna berikutnya akan mengambilnya.

Backend API berbeda. Men-deploy versi API baru seringkali berarti me-restart server aplikasi, menjalankan migrasi database, atau memperbarui konfigurasi infrastruktur. Itu membutuhkan waktu dan memiliki risikonya sendiri.

Ketika kedua ritme ini tidak selaras, kamu akan memiliki celah di mana frontend mengharapkan sesuatu dan API mengembalikan hal lain. Frontend memanggil endpoint yang sudah tidak ada. Atau API mulai mengembalikan field baru, dan frontend lama crash karena tidak bisa mem-parse respons.

Masalahnya semakin parah ketika tim yang berbeda memiliki frontend dan API. Tim frontend mungkin tidak tahu API berubah sampai seseorang melaporkan bug.

API Versioning Adalah Jawaban Klasik, Tapi Ada Biayanya

Solusi paling umum adalah melakukan versioning pada API. Kamu menambahkan prefix versi di URL, seperti /api/v1/orders dan /api/v2/orders. Frontend lama terus memanggil v1 sementara frontend baru pindah ke v2. Kedua versi hidup berdampingan sampai frontend lama sepenuhnya pensiun.

Ini berhasil, tapi tidak gratis. Mempertahankan beberapa versi API berarti tim backend kamu menanggung utang teknis. Setiap fitur baru perlu diimplementasikan di kedua versi, atau kamu perlu merencanakan jadwal depresiasi. Pengguna pada akhirnya perlu migrasi, dan migrasi itu sendiri adalah sebuah proyek.

Versioning adalah jaring pengaman, tapi berat. Untuk tim yang sering rilis, mempertahankan dua atau tiga versi API menjadi beban pada kecepatan pengembangan.

Feature Flags Memberikan Kontrol Lebih

Pendekatan yang lebih fleksibel adalah menggunakan feature flags. Kamu mengirimkan frontend baru dengan panggilan API baru yang sudah ada di bundle, tapi panggilan tersebut digerbangi oleh flag yang dimatikan. Pengguna mengunduh frontend baru, tapi mereka tidak pernah mengenai endpoint baru karena fiturnya tidak aktif.

Ketika tim API menyelesaikan deployment mereka, kamu menyalakan flag dari dashboard. Frontend mulai memanggil endpoint baru tanpa memerlukan unduhan baru. Tidak perlu review app store, tidak perlu purge cache CDN, tidak perlu meeting koordinasi.

Feature flags sangat berguna ketika frontend dan API dimiliki oleh tim yang berbeda. Tim frontend bisa rilis sesuai jadwal mereka, dan tim API bisa rilis sesuai jadwal mereka. Flag menjadi titik koordinasi tunggal.

Trade-off-nya adalah kamu mengirimkan kode yang belum aktif. Kode itu sudah diuji dan ditinjau, tapi hanya duduk di browser pengguna tanpa melakukan apa-apa. Jika ukuran bundle menjadi perhatian, kamu perlu berhati-hati tentang seberapa banyak kode mati yang kamu kirimkan.

Contract Testing Menangkap Masalah Sebelum Rilis

Feature flags dan versioning menangani masalah koordinasi setelah terjadi. Tapi kamu juga bisa menangkap ketidakcocokan sebelum frontend mencapai production. Mekanismenya adalah contract testing di pipeline CI/CD kamu.

Begini cara kerjanya. Selama build frontend, pipeline kamu menjalankan serangkaian contract test. Pengujian ini memeriksa bahwa respons API yang diharapkan frontend cocok dengan respons aktual dari API. Jika API mengembalikan field yang tidak diharapkan frontend, atau jika ada field yang hilang, atau jika tipe data berubah, contract test gagal dan pipeline berhenti.

Berikut adalah contoh minimal contract test dalam praktik:

// contract-test.js - dijalankan di CI sebelum men-deploy frontend
async function checkUserEndpoint() {
  const response = await fetch('https://api.example.com/v1/users/1');
  const data = await response.json();

  // Memeriksa bentuk yang diharapkan frontend
  if (typeof data.id !== 'number') {
    throw new Error('Expected id to be a number');
  }
  if (typeof data.name !== 'string') {
    throw new Error('Expected name to be a string');
  }
  if (!Array.isArray(data.roles)) {
    throw new Error('Expected roles to be an array');
  }

  console.log('Contract test passed: /users/:id matches frontend expectations');
}

checkUserEndpoint().catch(err => {
  console.error('Contract test failed:', err.message);
  process.exit(1);
});

Pengujian ini berjalan melawan API live di staging atau production. Jika API mengubah tipe field atau menghapus field yang diperlukan, pipeline gagal sebelum frontend mencapai pengguna.

Kamu menjalankan contract test ini terhadap versi API yang sedang berjalan di staging atau production, tergantung strategi kamu. Pengujian ini tidak memeriksa logika bisnis. Ia hanya memeriksa bentuk: apakah respons berisi field yang dibutuhkan frontend, dan apakah tipe datanya benar?

Contract testing bukan pengganti integration testing. Integration test memverifikasi bahwa seluruh sistem bekerja dengan benar. Contract test hanya memverifikasi bahwa frontend dan API dapat berkomunikasi tanpa crash. Tapi untuk masalah kompatibilitas, contract test adalah yang kamu butuhkan. Mereka cepat, berjalan di setiap pipeline, dan menangkap kelas ketidakcocokan frontend-backend yang paling umum.

Gabungkan Pendekatan Ini untuk Jaring Pengaman yang Praktis

Tidak ada satu teknik pun yang mencakup setiap skenario. API versioning menangani koeksistensi jangka panjang. Feature flags menangani ketidakcocokan waktu rilis. Contract testing menangkap masalah sebelum mencapai pengguna.

Diagram alir berikut dapat membantu kamu memutuskan pendekatan mana yang sesuai dengan situasi kamu:

flowchart TD A[Frontend dan API tidak sinkron?] --> B{Apakah ini perubahan besar yang memutuskan kompatibilitas?} B -->|Ya| C[Gunakan API versioning] B -->|Tidak| D{Apakah backend belum siap?} D -->|Ya| E[Gunakan feature flags] D -->|Tidak| F{Apakah kamu perlu menangkap ketidakcocokan sebelum rilis?} F -->|Ya| G[Tambahkan contract testing ke CI] F -->|Tidak| H[Tidak perlu tindakan] C --> I[Rencanakan jadwal depresiasi] E --> J[Kirim kode frontend tidak aktif, nyalakan flag nanti] G --> K[Pipeline gagal pada ketidakcocokan bentuk] I --> L[Kombinasikan dengan flags dan pengujian untuk jaring pengaman penuh] J --> L K --> L

Pengaturan praktis terlihat seperti ini:

  • Gunakan API versioning untuk perubahan besar yang memutuskan kompatibilitas yang mempengaruhi banyak konsumen.
  • Gunakan feature flags untuk koordinasi tingkat fitur antara tim frontend dan backend.
  • Tambahkan contract testing ke pipeline frontend kamu sebagai gerbang yang mencegah build yang tidak kompatibel untuk di-deploy.

Kombinasi ini memberi kamu beberapa lapis perlindungan tanpa memaksa setiap tim mengikuti jadwal rilis yang sama.

Daftar Periksa Cepat untuk Pipeline Kamu

Jika kamu baru pertama kali menyiapkan pemeriksaan kompatibilitas, berikut adalah daftar singkat untuk memulai:

  • Identifikasi endpoint API mana yang menjadi dependensi frontend kamu.
  • Tulis contract test yang memeriksa bentuk setiap respons.
  • Jalankan pengujian tersebut terhadap API staging atau production saat ini di pipeline CI frontend kamu.
  • Atur pipeline untuk gagal jika ada contract test yang gagal.
  • Untuk fitur yang belum siap di backend, bungkus panggilan frontend dalam feature flag.
  • Rencanakan jadwal depresiasi untuk versi API lama dan komunikasikan ke semua tim frontend.

Yang Paling Penting

Kompatibilitas frontend-backend bukanlah hal baru secara teknis. Ini adalah realitas sehari-hari bagi tim mana pun yang mengirimkan kode frontend terhadap API live. Risikonya bukanlah bahwa kode kamu memiliki bug. Risikonya adalah bahwa kode kamu benar, tapi ia berbicara dengan versi API yang salah.

Versioning, feature flags, dan contract testing masing-masing memecahkan bagian yang berbeda dari masalah itu. Gunakan mereka bersama-sama, dan pipeline kamu menjadi gerbang yang andal yang menjaga kode yang tidak kompatibel jauh dari pengguna.