REST API yang baik terasa seperti satu bahasa: begitu klien memahami satu endpoint, klien bisa menebak bentuk endpoint lainnya. Desain yang buruk bekerja sebaliknya — setiap endpoint punya aturan sendiri, dan setiap integrasi baru menuntut pembacaan dokumentasi dari nol. Karena API akan dikonsumsi aplikasi mobile, frontend JavaScript, dan layanan lain yang tidak kita kendalikan, keputusan desain harus diambil sebelum menulis kode. Chapter ini membahas aturan mainnya: penamaan resource, semantik method, idempotency, statelessness, dan pemilihan status code. Seluruh aturan tersebut akan kita pakai di sepanjang Section API Development dan pada proyek Proyek: REST API Manajemen Tugas.
Sumber Daya dan Penamaan URI #
REST menyebut setiap entitas yang dikelola API sebagai resource: tugas, pengguna, komentar. URI adalah alamat permanen sebuah resource, sehingga penamaannya harus nouns (kata benda), bukan verbs — kata kerja sudah dipegang oleh HTTP method. Bandingkan pola berikut pada API manajemen tugas:
| Kebutuhan | URI yang baik | URI yang buruk |
|---|---|---|
| Daftar semua tugas | GET /tugas | GET /api/getSemuaTugas |
| Detail satu tugas | GET /tugas/42 | GET /tugas/detail?id=42 |
| Tugas yang sudah selesai | GET /tugas?selesai=true | GET /tugas-sudah-selesai |
| Komentar milik satu tugas | GET /tugas/42/komentar | GET /getKomentar?taskId=42 |
Empat aturan penamaan bisa ditarik dari tabel di atas:
- Noun jamak untuk koleksi:
/tugas,/pengguna— bukan/getTugasatau/tugas-baru. - Kebab-case untuk nama lebih dari satu kata:
/daftar-tugas/, bukan/daftarTugas/atau/daftar_tugas/. - Relasi kepemilikan lewat path, filter lewat query string:
/tugas/42/komentarmenunjuk komentar milik tugas 42, sedangkan?selesai=truemenyaring hasil. - Hierarki hanya untuk kepemilikan, bukan untuk aksi:
/tugas/42/selesaikanadalah desain buruk karenaselesaikanadalah kata kerja.
Semantik Method HTTP #
Method HTTP bukan sekadar label — setiap method membawa janji perilaku yang dipahami semua klien, proxy, dan browser:
| Method | Pada koleksi /tugas | Pada item /tugas/42 | Idempotent |
|---|---|---|---|
| GET | baca daftar tugas | baca satu tugas | Ya |
| POST | buat tugas baru | tidak lazim | Tidak |
| PUT | ganti seluruh koleksi (jarang) | ganti seluruh isi tugas | Ya |
| PATCH | tidak lazim | ubah sebagian field | Tidak dijamin |
| DELETE | hapus koleksi (jarang) | hapus satu tugas | Ya |
Idempotency dalam Praktik #
Idempotency berarti request yang sama dikirim berkali-kali menghasilkan efek yang sama seperti dikirim sekali. GET, PUT, dan DELETE bersifat idempotent; POST tidak — POST yang diulang membuat duplikat. Sifat ini penting karena jaringan tidak andal: klien sering mengulang request yang dianggap gagal. Mari kita buktikan perilakunya dengan aplikasi FastAPI mini (dijalankan lewat TestClient, tanpa server):
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
tugas = [
{"id": 1, "judul": "Belajar Python", "selesai": False},
]
@app.get("/tugas")
def daftar_tugas():
return tugas
@app.post("/tugas")
def buat_tugas():
tugas_baru = {"id": len(tugas) + 1, "judul": "Tugas baru", "selesai": False}
tugas.append(tugas_baru)
return tugas_baru
client = TestClient(app)
print(client.get("/tugas").json())
print(client.get("/tugas").json())
print(client.post("/tugas").json()["id"])
print(client.post("/tugas").json()["id"])Output yang Dihasilkan:
[{'id': 1, 'judul': 'Belajar Python', 'selesai': False}]
[{'id': 1, 'judul': 'Belajar Python', 'selesai': False}]
2
3
[{'id': 1, 'judul': 'Belajar Python', 'selesai': False}, {'id': 2, 'judul': 'Tugas baru', 'selesai': False}, {'id': 3, 'judul': 'Tugas baru', 'selesai': False}]Mari kita telaah baris-baris pentingnya:
- Baris 10 (
@app.get("/tugas")): fungsidaftar_tugashanya membaca listtugastanpa mengubah apa pun — dua panggilan GET pada baris 24-25 menghasilkan output identik. - Baris 15 (
@app.post("/tugas")): fungsibuat_tugasmenambah elemen baru ketugassetiap kali dipanggil — dua panggilan POST pada baris 27-28 menghasilkanidberbeda (2lalu3). - Baris 18 (
tugas.append(tugas_baru)): baris inilah efek samping yang membuat POST tidak idempotent; fungsi GET tidak punya baris setara.
Stateless dan Pemilihan Status Code #
Server REST bersifat stateless: server tidak mengingat request sebelumnya, sehingga setiap request harus membawa informasi lengkap — termasuk kredensial. Konsekuensinya positif: server dapat direplikasi dan bebannya diseimbangkan tanpa session yang menempel pada satu mesin. State seperti “sudah login” berpindah menjadi tanggung jawab klien, dibawa setiap request lewat header — pola yang akan kita praktikkan pada chapter Authentication dan Authorization.
Setiap response juga harus memilih status code dari keluarga yang benar: 2xx untuk sukses, 3xx untuk redirect, 4xx untuk kesalahan klien, 5xx untuk kesalahan server. Aturan praktis untuk CRUD: 201 saat POST berhasil membuat resource, 204 saat DELETE berhasil, 404 saat resource tidak ada, 422 saat body tidak lolos validasi — pembahasan lengkapnya ada di chapter Status Codes dan Error Responses. Terakhir, API yang hidup lama membutuhkan strategi versi seperti /v1/tugas/ — kapan versi baru diterbitkan dan cara memensiunkan versi lama dibahas di chapter Versioning dan Backward Compatibility.