Delapan Pola REST API yang Membuatnya Bisa Ditebak Tanpa Buka Dokumentasi

Abd. Asis
Delapan Pola REST API yang Membuatnya Bisa Ditebak Tanpa Buka Dokumentasi

Tiga jam saya habiskan untuk satu endpoint milik mitra. Responsnya 200 OK, jadi kode saya menganggap semuanya beres. Ternyata di dalam body ada {"status": "error", "message": "product not found"}. Setelah saya perbaiki pemeriksaan itu, muncul masalah kedua: setiap kali koneksi putus dan saya mengirim ulang request yang sama, jumlah order di sisi mereka bertambah. Dua retry, dua order.

Tidak ada satu pun aturan REST yang dilanggar di API itu. Endpoint-nya jalan, JSON-nya valid, dokumentasinya ada. Yang bermasalah adalah hal yang lebih sulit ditulis di dokumen: perilakunya tidak bisa ditebak.

Delapan pola di bawah ini semuanya soal itu. Bukan soal apakah API-mu "RESTful", tapi apakah orang lain bisa memakainya tanpa menebak-nebak.

1. URL menamai benda, method menamai pekerjaan

Kesalahan yang paling sering saya temui adalah endpoint bergaya fungsi: /getUsers, /createOrder, /deleteProduct. Awalnya terasa jelas. Masalahnya, URL jadi menjelaskan aksi, padahal HTTP sudah punya alat untuk itu.

Pisahkan perannya. URL menyebut benda, method menyebut apa yang kamu lakukan padanya.

CodeCODE
GET    /orders        daftar order
POST   /orders        buat order baru
GET    /orders/{id}   ambil satu order
PUT    /orders/{id}   ganti seluruh isi order
DELETE /orders/{id}   hapus order

Pola ini juga lebih tahan umur. Satu resource bisa melayani banyak operasi tanpa kamu mengarang URL baru setiap kali ada kebutuhan.

2. Satu konvensi penamaan, dipakai sampai ujung

Ambil contoh: satu bagian API memakai /user, bagian lain /customers, bagian ketiga /customer-profiles. Masing-masing jalan sendiri, tapi sekarang setiap orang yang integrasi harus menghafal aturanmu.

Pilih satu gaya untuk resource yang namanya lebih dari satu kata, lalu pakai di semua tempat. customer-profiles atau customerProfiles atau customer_profiles, pilih satu. Yang mana pun tidak masalah, yang penting tidak campur.

Konsistensi ini bukan soal kerapian. Efeknya langsung: orang bisa menebak endpoint yang belum pernah dia buka.

3. Method dipakai sesuai artinya, bukan sesuai yang bikin jalan

Butuh update user, dan di satu tempat kamu memakai POST, di tempat lain PUT, di tempat lain lagi PATCH. Ketiganya "berhasil". Tapi klien sekarang harus mempelajari aturan buatanmu, bukan mempercayai HTTP.

MethodArtinyaBerulang aman?
GETambil data, tanpa efek sampingya
POSTbuat resource baru atau picu prosestidak
PUTganti seluruh representasi resourceya
PATCHubah sebagian fieldya, kalau dirancang begitu
DELETEhapus resourceya

Perbedaan PATCH dan PUT paling sering dikaburkan:

CodeHTTP
PATCH /users/42
{ "email": "[email protected]" }

PUT /users/42
{ "name": "Abd. Asis", "email": "[email protected]", "role": "admin" }

Yang pertama mengubah satu field dan membiarkan sisanya. Yang kedua mengganti seluruh isi record, jadi field yang tidak kamu kirim akan hilang atau kembali ke nilai default.

Di balik semua ini ada idempotensi: mengirim GET, PUT, atau DELETE lima kali hasilnya harus sama dengan sekali. POST sengaja melanggar aturan itu, dan di situlah muncul order dobel saat retry. Jaringan putus, klien mengulang, timeout terjadi. Pilih method berdasarkan artinya, bukan berdasarkan mana yang kebetulan bikin endpoint jalan.

4. Status code jangan bohong

Contoh yang benar-benar menyakiti integrator: HTTP 200, tapi isi body bilang operasinya gagal karena produk tidak ditemukan. Klien sekarang harus memeriksa dua tempat untuk tahu apa yang sebenarnya terjadi.

Biarkan status code membawa hasil sebenarnya. 2xx untuk berhasil, 4xx kalau permintaan klien yang salah, 5xx kalau servermu yang salah.

KodeKapan dipakai
200 / 201berhasil, 201 saat resource baru dibuat
204berhasil, tidak ada isi untuk dikembalikan
400payload tidak valid secara bentuk
401 / 403belum login / sudah login tapi tidak berhak
404resource tidak ada
409konflik keadaan, misalnya data duplikat
422validasi gagal pada isi permintaan
429kena batas laju
500kesalahan di sisi server

Kamu tidak perlu menghafal semuanya. Yang perlu: status code yang benar-benar mewakili hasilnya, dan tidak mengarang protokol error sendiri di atas HTTP.

5. Bentuk error seragam

Status code memberi tahu kategori kegagalan. Klien biasanya butuh lebih dari itu. Bandingkan dua respons ini:

{}JSON
{ "error": "Something went wrong" }
{}JSON
{
  "code": "PRODUCT_NOT_FOUND",
  "message": "Tidak ada produk dengan ID tersebut",
  "status": 404
}

Yang kedua jauh lebih berguna: aplikasi bisa bereaksi pada code, manusia bisa membaca message, dan yang men-debug punya pegangan. Untuk kegagalan validasi, sebut field mana yang salah, bukan hanya "permintaan tidak valid":

{}JSON
{
  "code": "VALIDATION_FAILED",
  "message": "Ada 2 field yang perlu diperbaiki",
  "status": 422,
  "errors": {
    "email": ["Format email tidak valid"],
    "qty": ["Harus bilangan bulat minimal 1"]
  }
}

Formatnya bebas kamu tentukan. Yang wajib adalah bentuknya sama di semua endpoint, supaya klien bisa menulis satu penangan error untuk seluruh API.

6. Filter masuk query, bukan ke dalam path

Mulai dari /products. Lalu tambah kategori di path. Lalu status stok. Lalu rentang harga. Lalu pencarian. Lalu urutan. Setahun kemudian URL-nya sudah tidak bisa dibaca manusia.

Kriteria opsional tempatnya di query string:

CodeHTTP
GET /products?category=sepatu&inStock=true&sort=price&page=2

Path menyebut benda, query mempersempit hasil. Satu hal yang perlu dihindari: jangan pakai query untuk menyamar sebagai aksi. GET /products?action=delete membuat method berbohong tentang apa yang sedang terjadi, dan setiap alat di jalan (cache, proxy, crawler) akan salah mengira request itu aman diulang.

7. Perubahan API dilakukan dengan sadar

API tidak pernah beku. Respons yang sempurna hari ini bisa perlu berubah enam bulan lagi. Yang berbahaya adalah mengubahnya tanpa memikirkan klien yang sudah bergantung padamu.

Contoh nyata: dulu price berupa angka, sekarang kamu ingin price jadi objek berisi nilai dan mata uang. Itu bukan "cuma menambah field". Strukturnya berubah, dan klien lama akan rusak.

Sebelum buru-buru membuat versi baru, tanya dulu apakah memang perlu.

PerubahanAman?
Menambah field opsional di responsbiasanya aman
Menambah parameter query opsionalbiasanya aman
Mengubah tipe data sebuah fieldtidak
Menghapus atau mengganti nama fieldtidak
Mengubah arti status codetidak
Mengubah struktur paginasitidak

Kalau memang perlu versi baru, pilih satu mekanisme dan pakai konsisten: versi di URL, versi di header, terserah. Yang penting ada jalur migrasi, bukan pengumuman mendadak bahwa klien harus berubah minggu ini.

8. Format request dan respons konsisten

Satu endpoint mengembalikan created_at, endpoint lain createdAt, endpoint ketiga date_created. Semuanya JSON yang sah. Tapi sekarang setiap klien harus mengingat mana yang berlaku di mana.

Masalah yang sama muncul di format tanggal, bentuk paginasi, struktur error, dan penamaan properti. Jadi tetapkan sekali, lalu pegang:

  • satu gaya JSON untuk seluruh API
  • satu konvensi penamaan properti
  • satu bentuk respons error
  • satu pola paginasi dan filter
  • satu format tanggal, sebutkan zona waktunya

Tujuannya bukan membuat buku aturan setebal dokumen kontrak. Tujuannya supaya endpoint berikutnya terasa familier. Setelah orang memahami satu bagian API-mu, dia seharusnya bisa menebak sisanya dengan benar.

Kalau kamu bekerja di Laravel, pembungkusan respons lewat API Resource membantu menjaga bentuk ini tetap seragam tanpa mengulang kode di setiap controller. Sisi lain yang sering terlewat adalah pengujian: perubahan kecil di resource bisa mengubah kontrak tanpa ada yang sadar, dan itu yang saya tulis di mendeteksi schema drift pada API PHP.

Yang sebenarnya dikejar bukan gelar "RESTful"

Banyak developer mengukur API dari seberapa patuh ia pada teori REST. Itu berguna, tapi bukan intinya. API tidak jadi baik hanya karena GET, POST, PUT, dan DELETE-nya dipakai dengan benar.

API yang baik adalah API yang bisa dipakai orang tanpa harus membuka dokumentasi setiap sepuluh menit. Nama resource masuk akal. Method berperilaku seperti dugaan. Status code berarti sesuatu. Error punya bentuk yang tetap. Filter bekerja sama di semua tempat. Dan perubahan tidak diam-diam merusak orang yang sudah bergantung padamu.

Jadi sebelum menulis endpoint pertama, jawab dulu pertanyaan besarnya: bagaimana resource dinamai, bagaimana koleksi diperlakukan, bagaimana filter berperilaku, method mana yang benar-benar dipakai, bagaimana error terlihat, bagaimana status code diperlakukan, dan bagaimana API ini akan berevolusi.

Begitu jawabannya jelas, menulis endpoint jadi bagian yang mudah. Sisanya cuma disiplin untuk tidak menyimpang di endpoint kesepuluh, ketika tenggat sudah dekat dan jalan pintas terlihat menggoda.

Abd. Asis
Ditulis oleh
Abd. Asis

Software Developer dari Madura. Menulis tentang PHP, Laravel, dan pengembangan web modern dalam Bahasa Indonesia.