Merancang API yang Tidak Mudah Merepotkan
API biasanya dimulai dari kebutuhan sederhana: mengambil daftar, membuat data, lalu memperbaruinya. Kerumitan muncul setelah API dipakai oleh web, mobile, integrasi lain, dan versi aplikasi yang tidak semuanya dapat diperbarui bersamaan.
Saya tidak punya aturan yang cocok untuk semua API. Namun beberapa kebiasaan kecil cukup membantu agar perubahan tidak terus-menerus merepotkan pemakainya.
Gunakan nama dari domain pengguna
Nama endpoint dan field sebaiknya mengikuti istilah yang dikenal produk, bukan nama tabel atau struktur internal backend.
GET /courses/{courseId}/lessons lebih mudah dipahami daripada:
GET /course_content_relations?parent_id=123 Database dapat berubah tanpa memaksa bahasa API ikut berubah. API adalah kontrak dengan pemakai, bukan gambaran langsung tentang cara server menyimpan data.
Konsistensi lebih berharga daripada kreativitas
Jika satu endpoint menggunakan createdAt, endpoint lain sebaiknya tidak tiba-tiba menggunakan created_at. Hal yang sama berlaku untuk pagination, filtering, error, dan penamaan ID.
Pilih pola sederhana lalu gunakan secara konsisten:
{
"data": [],
"pagination": {
"page": 1,
"pageSize": 20,
"total": 84
}
} Konsistensi mengurangi dokumentasi yang harus diingat dan memungkinkan client membuat helper yang dapat digunakan ulang.
Bedakan field yang hilang dan bernilai kosong
Pada operasi update, undefined, null, dan string kosong dapat memiliki arti berbeda.
{
"displayName": null
} Apakah ini berarti menghapus nama, tidak mengubah nama, atau input tidak valid? Tentukan perilakunya dan dokumentasikan. Ketidakjelasan semacam ini sering menyebabkan client menghapus data tanpa sengaja.
Untuk partial update, field yang tidak dikirim biasanya berarti tidak berubah. null dapat dipakai
untuk menghapus nilai hanya jika field tersebut memang nullable.
Berikan error yang dapat ditindaklanjuti
Status HTTP penting, tetapi client juga membutuhkan kode yang stabil dan detail yang relevan.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Some fields are invalid.",
"fields": {
"email": "Email is already registered."
},
"requestId": "req_01J..."
}
} Pesan dapat berubah atau diterjemahkan. code sebaiknya tetap stabil agar aplikasi dapat menentukan
perilaku tanpa membandingkan teks error.
Pagination harus dipikirkan sejak awal
Endpoint daftar yang awalnya hanya memiliki sepuluh item dapat tumbuh menjadi ribuan. Menambahkan pagination belakangan bisa menjadi breaking change.
Offset pagination mudah digunakan untuk data yang tidak banyak berubah. Cursor pagination lebih cocok untuk feed atau data besar yang sering mendapat item baru.
Yang penting bukan memilih pola paling canggih, tetapi memberikan urutan yang stabil. Pagination tanpa ordering yang jelas dapat menampilkan item ganda atau melewatkan data.
Operasi tulis perlu memikirkan pengulangan request
Client dapat mengirim request yang sama lebih dari sekali karena timeout atau retry. Untuk operasi seperti pembayaran, absensi, dan pembuatan transaksi, gunakan idempotency key.
POST /payments
Idempotency-Key: payment-attempt-018f Server dapat mengenali pengulangan dan mengembalikan hasil sebelumnya tanpa membuat transaksi baru.
Jangan menghapus field terlalu cepat
Mobile app versi lama dapat tetap aktif berbulan-bulan. Mengganti nama atau menghapus field secara langsung berisiko merusak client yang belum diperbarui.
Perubahan additive biasanya lebih aman:
- Tambahkan field baru.
- Perbarui client agar menggunakannya.
- Pantau penggunaan field lama.
- Tandai field lama sebagai deprecated.
- Hapus setelah pemakai memiliki waktu migrasi yang cukup.
Versioning membantu untuk perubahan besar, tetapi bukan alasan untuk membuat kontrak berubah tanpa rencana migrasi.
Dokumentasi perlu contoh nyata
Daftar endpoint belum tentu cukup. Sertakan contoh request, response berhasil, error umum, dan catatan tentang permission.
Dokumentasi yang baik memungkinkan seseorang mencoba alur dasar tanpa harus membaca source code server. Jika contoh dokumentasi dijalankan sebagai test, kemungkinan isinya menjadi usang juga lebih kecil.
Kesimpulan
API yang nyaman biasanya terasa membosankan dengan cara yang baik. Polanya konsisten, error-nya jelas, dan perubahan dapat diprediksi.
Saya mencoba melihat API dari sisi orang yang harus memakainya tanpa mengetahui seluruh isi backend. Jika kontraknya dapat dipahami dari nama, type, dan beberapa contoh, sebagian besar pekerjaan sudah berada di arah yang benar.