Desain API yang Baik — API

API yang baik adalah API yang mudah dipahami, konsisten, dan predictable. Prinsip RESTful: Gunakan noun, bukan verb: /users bukan /getUsers Gunakan plural…

API yang baik itu gampang ditebak: kalau kamu tahu satu endpoint-nya, kamu bisa menebak yang lain tanpa membuka dokumentasi. Bayangin denah perpustakaan yang rapi. Raknya diberi nama benda ("Novel", "Penulis"), nomor bukunya urut, dan cara meminjam di semua rak sama. Begitu paham satu rak, kamu paham semuanya. API yang asal-asalan seperti perpustakaan yang tiap raknya punya aturan sendiri.

🧪 Tebakan cepat: ada endpoint usulan POST /deleteBook?id=9. Ada berapa masalah di situ? Tebak dulu, jawabannya ada di bagian "Kata benda jamak, method sebagai kata kerja".

Kata benda jamak, method sebagai kata kerja

Path menunjuk benda (resource), method menyebut aksinya. Kumpulannya ditulis jamak, satu bendanya ditunjuk dengan id di path:

Kurang tepat Lebih baik Kenapa
GET /getBooks GET /books GET sudah berarti "ambil"
GET /book/1 GET /books/1 koleksinya jamak, bukunya nomor 1 di koleksi itu
POST /books/create POST /books POST ke koleksi sudah berarti "buat"
PUT /Books/7/Update_Stock PATCH /books/7 dengan body {"stock": 7} huruf kecil, tanpa kata kerja, ubah sebagian pakai PATCH

POST /deleteBook?id=9 punya tiga masalah: ada kata kerja di URL (delete), method-nya POST padahal aksinya menghapus, dan id buku ditaruh di query, padahal satu benda ditunjuk lewat path. Versi rapinya DELETE /books/9. Itu jawaban tebakannya.

Pola yang sama berlaku untuk resource apa pun: semua postingan blog diambil dengan GET /api/posts, bukan GET /api/getPost.

Nama path juga dibuat seragam: huruf kecil semua, kata disambung tanda hubung kalau perlu (/best-sellers), tanpa akhiran .json.

Nesting secukupnya

Benda yang "milik" benda lain boleh ditulis bersarang (nested), cukup satu tingkat:

GET /authors/2/books
GET /books/7/reviews

GET /authors/2/books/7/reviews terlalu dalam. Buku 7 sudah punya alamat sendiri, jadi ulasannya cukup GET /books/7/reviews. Pegangannya: paling banyak satu induk di depan, /induk/id/anak.

Menyaring, mengurutkan, dan memotong per halaman gak butuh path baru, cukup query string, seperti di pelajaran URL & Endpoint dan Pagination: GET /books?author_id=2&sort=-price&page=2. Jangan bikin /getBooksByAuthor/2.

Response yang konsisten

Bentuk jawabannya sama di semua endpoint, jadi frontend cukup menulis satu cara membaca:

Situasi Status Body
Daftar 200 {"data": [...], "meta": {...}}
Satu benda 200 {"data": {...}}
Dibuat 201 {"data": {...}, "message": "Book created"}
Gak ketemu 404 {"error": "Book not found"}
app.get("/books/:id", (req, res) => {
  const book = books.find((b) => b.id === Number(req.params.id));
  if (!book) return res.status(404).json({ error: "Book not found" });
  res.json({ data: book });
});

Response seperti {"s": 1, "d": [{"n": "Budi"}]} memang hemat beberapa byte, tapi nama key-nya gak deskriptif: orang yang membacanya harus menebak s, d, dan n itu apa. Tulis {"success": true, "data": [{"name": "Budi"}]}.

Versioning: /api/v1

API itu janji ke semua client. Kalau suatu hari bentuk response harus berubah, misalnya title diganti judul, aplikasi HP versi lama yang masih membaca title langsung rusak. Karena itu path diberi versi:

GET /api/v1/books
GET /api/v2/books

Perubahan yang merusak (breaking change) masuk ke /api/v2, sedangkan /api/v1 tetap jalan untuk client lama. Ini disebut menjaga backward compatibility. Detailnya ada di pelajaran API Versioning.

⚠️ Jebakan yang sering ketemu

TL;DR: API yang baik gampang ditebak. Path berisi kata benda jamak (/books, /books/9), aksinya lewat method (GET, POST, PUT/PATCH, DELETE), jadi gak ada kata kerja di URL: POST /deleteBook?id=9 jadi DELETE /books/9. Huruf kecil, nesting paling banyak satu induk (/books/7/reviews), dan saring atau urutkan lewat query. Response-nya konsisten dan nama key-nya deskriptif: {"data": ...} untuk sukses, {"error": "..."} dengan status yang pas untuk gagal, 201 plus message untuk data baru. Beri versi di path (/api/v1/posts) supaya perubahan besar bisa masuk ke v2 tanpa merusak client lama (backward compatibility).

Yang akan kamu pelajari