API yang enak dipakai dimulai dari respons yang jelas.
Bentuk data yang konsisten membantu frontend dan backend bekerja bersama. Mulai dari kontrak TypeScript, validasi respons, hingga pesan error yang berguna.
Menghubungkan frontend dengan backend bukan hanya soal memanggil sebuah URL. Kedua sisi perlu sepakat tentang arti data, bentuk kesalahan, dan tindakan yang mungkin dilakukan setelah respons diterima.
Untuk proyek kecil, kesepakatan itu bisa dimulai dari satu contoh respons sukses dan satu contoh respons gagal. Artikel ini memakai kontrak sederhana sebagai bahan latihan; sesuaikan dengan kebutuhan API Anda.
Bedakan hasil sukses dan gagal
Gunakan bentuk respons yang membuat kedua keadaan mudah dibedakan. Dalam TypeScript, sebuah discriminated union bisa membantu:
type ApiResult<T> =
| { ok: true; data: T }
| {
ok: false;
error: { code: string; message: string };
};
interface Project {
id: string;
name: string;
}
function describeResult(result: ApiResult<Project>): string {
if (!result.ok) return result.error.message;
return `Project ${result.data.name} siap dibuka.`;
}
Properti ok memberikan pembeda yang jelas. Setelah memeriksa nilainya, kode dapat mengakses properti yang sesuai tanpa menebak apakah data atau error tersedia.
Kontrak ini tidak menggantikan status HTTP. Tentukan juga status yang digunakan untuk sukses, input tidak valid, akses ditolak, dan resource yang tidak ditemukan. Dokumentasikan pasangan status dan bentuk responsnya agar tidak saling bertentangan.
Ingat bahwa tipe tidak memvalidasi jaringan
Menulis response as Project tidak memeriksa data yang datang dari server. TypeScript membantu saat pengembangan, sedangkan respons jaringan baru diketahui saat aplikasi berjalan.
Untuk objek kecil, pemeriksaan eksplisit bisa menjadi awal:
function isProject(value: unknown): value is Project {
if (typeof value !== "object" || value === null) {
return false;
}
return (
"id" in value &&
typeof value.id === "string" &&
"name" in value &&
typeof value.name === "string"
);
}
Pemeriksaan ini hanya memastikan bentuk dasar. Ia belum memastikan ID tidak kosong atau nama memenuhi aturan bisnis. Untuk struktur yang bertingkat dan banyak endpoint, pertimbangkan validator skema agar aturan dapat dipakai ulang.
Buat error yang membantu tindakan berikutnya
Pisahkan kode kesalahan yang dibaca aplikasi dari pesan yang dibaca pengguna. Misalnya, kode SLOT_UNAVAILABLE dapat memicu pemuatan ulang jadwal, sementara pesannya menjelaskan bahwa pengguna perlu memilih waktu lain.
Jangan mengirim detail internal seperti query database, token, atau stack trace sebagai pesan untuk pengguna. Simpan informasi diagnosis pada sistem pencatatan yang sesuai, lalu sertakan ID permintaan apabila dibutuhkan untuk penelusuran.
Di frontend, bedakan pula kegagalan jaringan dengan respons error dari server. Keduanya mungkin membutuhkan penjelasan dan opsi pemulihan yang berbeda.
Rancang perubahan kontrak
Kontrak API dapat berubah. Sebelum mengganti nama atau tipe sebuah properti, periksa semua pemakainya: web, aplikasi mobile, integrasi, dan proses latar belakang.
Perubahan yang tampak kecil di backend bisa memutus aplikasi mobile yang belum diperbarui. Bila diperlukan, sediakan masa transisi, pertahankan properti lama untuk sementara, dan dokumentasikan kapan dukungannya berakhir.
Jangan otomatis menganggap penambahan properti selalu aman. Konsumen dengan validasi sangat ketat mungkin menolak properti yang belum dikenalnya. Kesepakatan tentang kompatibilitas juga bagian dari kontrak.
Periksa batas integrasinya
Gunakan contoh respons sebagai dasar pengujian yang berarti:
- Respons sukses dapat dibaca dan ditampilkan.
- Kesalahan yang dikenal menghasilkan tindakan yang sesuai.
- Respons dengan bentuk tidak valid ditangani tanpa merusak halaman.
- Pengguna dapat memahami apa yang terjadi ketika koneksi gagal.
Tujuannya bukan membuat pembungkus untuk setiap baris kode. Tujuannya adalah menjaga batas tempat dua bagian aplikasi saling bergantung tetap jelas dan dapat dipercaya.