1. Apa itu REST (Representational State Transfer)?
REST adalah gaya arsitektur perangkat lunak untuk komunikasi data antar sistem terdistribusi (biasanya frontend ke backend). REST bersifat **Stateless**, artinya setiap HTTP request yang dikirimkan client harus membawa seluruh informasi yang dibutuhkan server untuk memprosesnya. Server tidak menyimpan memori percakapan client antar request.
2. Aturan Emas Penamaan Resource URI
Dalam REST, URL mewakili **Kata Benda (Resource/Entities)**, bukan kata kerja atau aksi. Kata kerja dinyatakan oleh **HTTP Method**.
| 1 | // ❌ PENAMAAN SALAH (Menggunakan kata kerja di URI) |
| 2 | // GET /api/getAllUsers |
| 3 | // POST /api/createUser |
| 4 | // POST /api/deleteUserById?id=12 |
| 5 | |
| 6 | // ✅ PENAMAAN REST YANG BENAR (Kata Benda Plural + HTTP Method) |
| 7 | // GET /api/users -> Mengambil daftar semua user |
| 8 | // POST /api/users -> Membuat user baru |
| 9 | // GET /api/users/12 -> Mengambil detail user id 12 |
| 10 | // PATCH /api/users/12 -> Mengubah sebagian data user id 12 |
| 11 | // DELETE /api/users/12 -> Menghapus user id 12 |
| 12 | // GET /api/users/12/courses -> Mengambil relasi kursus milik user 12 |
3. Standarisasi Response Envelope
API kelas produksi yang baik selalu membungkus hasil respons dalam format *Envelope* yang seragam agar client (frontend/mobile) dapat memprediksi struktur data baik saat operasi berhasil maupun gagal.
| 1 | // Respons Sukses |
| 2 | { |
| 3 | "success": true, |
| 4 | "data": { |
| 5 | "id": "usr_102", |
| 6 | "username": "heru_dev", |
| 7 | "totalXp": 450 |
| 8 | } |
| 9 | } |
| 10 | |
| 11 | // Respons Gagal / Error |
| 12 | { |
| 13 | "success": false, |
| 14 | "error": { |
| 15 | "code": "USER_NOT_FOUND", |
| 16 | "message": "Pengguna dengan ID tersebut tidak ditemukan di basis data." |
| 17 | } |
| 18 | } |
4. Simulasi Dispatcher Request REST di Terminal
| 1 | function mockApiRouter(method, path, body = null) { |
| 2 | const usersDb = [ |
| 3 | { id: 1, name: "Alice", role: "student" }, |
| 4 | { id: 2, name: "Bob", role: "mentor" } |
| 5 | ]; |
| 6 | |
| 7 | if (method === "GET" && path === "/api/users") { |
| 8 | return { status: 200, body: { success: true, data: usersDb } }; |
| 9 | } |
| 10 | |
| 11 | if (method === "POST" && path === "/api/users") { |
| 12 | if (!body || !body.name) { |
| 13 | return { status: 400, body: { success: false, error: "Name is required" } }; |
| 14 | } |
| 15 | const newUser = { id: usersDb.length + 1, ...body }; |
| 16 | return { status: 201, body: { success: true, data: newUser } }; |
| 17 | } |
| 18 | |
| 19 | return { status: 404, body: { success: false, error: "Route not found" } }; |
| 20 | } |
| 21 | |
| 22 | console.log("=== TEST GET /api/users ==="); |
| 23 | console.log(mockApiRouter("GET", "/api/users")); |
| 24 | |
| 25 | console.log("=== TEST POST /api/users (Create) ==="); |
| 26 | console.log(mockApiRouter("POST", "/api/users", { name: "Charlie", role: "developer" })); |