Panduan Desain REST API: Prinsip, Pola, dan Contoh Praktis
Pelajari cara mendesain REST API yang konsisten, aman, dan mudah dipakai: prinsip REST, penamaan resource, HTTP method, status code, versioning, pagination, hingga studi kasus nyata.
Panji Ihsanudin Fajri
18 min read1 reads

Contents
- Apa itu REST API?
- Cara kerja REST API
- Kenapa desain REST API yang baik itu penting
- Prinsip dasar desain REST API
- Client-server
- Stateless
- Cacheable
- Uniform interface
- Layered system
- Code on demand (opsional)
- Mendesain URL dan resource yang konsisten
- Aturan penamaan yang terbukti
- Kapan aturan boleh dilanggar
- HTTP method dan status code: pakai yang semestinya
- Method dan sifatnya
- Status code yang wajib dikuasai
- Versioning, pagination, filtering, dan sorting
- Versioning: rencanakan sebelum dibutuhkan
- Pagination: jangan pernah kembalikan "semua data"
- Filtering, sorting, dan field selection
- Format respons dan error handling yang konsisten
- Envelope respons seragam
- Error yang benar-benar membantu
- Keamanan: autentikasi, otorisasi, dan rate limiting
- Pilih mekanisme autentikasi yang sesuai
- Otorisasi: autentikasi bukan otorisasi
- Rate limiting dan kuota
- Daftar periksa keamanan minimum
- Studi kasus: mendesain API untuk aplikasi e-commerce
- Daftar endpoint
- Contoh alur checkout
- Kesalahan umum dalam desain REST API
- FAQ
- Apakah REST API harus selalu memakai JSON?
- Kapan memakai PUT dan kapan PATCH?
- Bagaimana cara versioning API yang paling aman?
- Apakah HATEOAS wajib agar bisa disebut REST API?
- Berapa banyak data yang sebaiknya dikembalikan per halaman?
- Kesimpulan
Hampir setiap aplikasi modern berbicara lewat REST API: aplikasi mobile mengambil data katalog, dashboard web menyimpan laporan, sampai layanan pihak ketiga menarik data pelanggan. Masalahnya, banyak API dirancang asal jalan — endpoint tidak konsisten, status code dipakai sembarangan, dan pesan error yang tidak membantu siapa pun. Akibatnya, integrasi jadi mahal, bug menumpuk, dan setiap perubahan kecil menakutkan.
Artikel ini adalah panduan desain REST API yang sistematis dan praktis. Kamu akan mempelajari prinsip dasar REST, cara menamai resource dan menyusun URL yang konsisten, pemakaian HTTP method dan status code yang tepat, strategi versioning dan pagination, format error yang seragam, sampai aspek keamanan. Di bagian akhir ada studi kasus lengkap: mendesain API untuk aplikasi e-commerce dari nol.
Ringkasan: REST API yang baik memperlakukan URL sebagai resource (kata benda), bukan aksi. HTTP method dan status code punya makna baku — pakai sesuai spesifikasinya. Konsistensi format respons dan error menghemat waktu semua konsumen API. Versioning, pagination, dan rate limiting bukan fitur tambahan, melainkan kebutuhan sejak hari pertama. Keamanan (HTTPS, autentikasi, otorisasi) tidak bisa ditawar.

Apa itu REST API?
REST (Representational State Transfer) adalah gaya arsitektur untuk membangun layanan web yang diperkenalkan Roy Fielding dalam disertasi doktoralnya pada tahun 2000. REST API adalah API yang mengikuti prinsip-prinsip arsitektur tersebut dan berkomunikasi melalui HTTP: client mengirim request ke sebuah URL yang mewakili resource, server memprosesnya, lalu mengembalikan representasi resource tersebut — umumnya dalam format JSON.
Tiga istilah itu layak dipahami dengan tepat. Resource adalah konsep atau objek yang ingin kamu ekspos, misalnya pengguna, produk, atau pesanan. Representasi adalah wujud resource pada satu titik waktu — data JSON yang dikirim bolak-balik. State transfer berarti setiap request membawa konteksnya sendiri; server tidak menyimpan ingatan tentang request sebelumnya.
Cara kerja REST API

Alurnya selalu sama. Client membangun sebuah HTTP request yang terdiri dari method (GET, POST, dan kawan-kawan), URL resource, header (misalnya Authorization dan Content-Type), dan opsional body. Server menerima request, menjalankan logika bisnis, lalu mengembalikan HTTP response berisi status code, header, dan body.
Contoh mentah pertukaran ini terlihat seperti berikut:
GET /v1/products/42 HTTP/1.1
Host: api.toko.id
Authorization: Bearer eyJhbGciOi...
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=3600
{
"id": 42,
"name": "Kopi Arabika 200g",
"price": 85000,
"stock": 120
}
Perhatikan dua hal. Pertama, request bersifat stateless: token autentikasi dikirim di setiap request karena server tidak mengingat sesi sebelumnya. Kedua, respons bersifat self-descriptive: status code 200 OK dan header Content-Type memberi tahu client cara menafsirkan body tanpa dokumentasi tambahan.
Kenapa desain REST API yang baik itu penting
API adalah kontrak. Sekali dipublikasikan dan dipakai oleh aplikasi mobile, dashboard web, partner bisnis, atau skrip otomasi, mengubahnya jadi mahal. Desain yang buruk tidak hilang — ia menumpuk menjadi technical debt yang dibayar setiap kali ada integrasi baru.
Ada empat alasan konkret kenapa investasi di desain terbayar lunas:
- Biaya integrasi turun. API yang konsisten bisa ditebak polanya. Developer yang sudah memakai satu endpoint tidak perlu membaca ulang dokumentasi untuk endpoint berikutnya.
- Bug berkurang. Status code yang tepat membuat client menangani kegagalan dengan benar — retry untuk
503, tampilkan form login untuk401, bukan menebak-nebak dari body respons. - Perubahan aman. Versioning yang direncanakan sejak awal membuat kamu bisa merilis v2 tanpa memutus aplikasi lama yang masih memakai v1.
- Konsumen makin beragam. Hari ini konsumen API bukan cuma aplikasi buatan manusia — AI agent juga memanggil API lewat tool use. Respons yang konsisten dan terdokumentasi membuat API-mu langsung bisa dipakai agent. Kalau kamu membangun fitur AI di atas API, panduan lengkap prompt engineering membahas cara merancang instruksi yang konsisten untuk model bahasa.
Prinsip dasar desain REST API
Fielding merumuskan enam batasan (constraints) arsitektur REST. Kamu tidak perlu menghafalnya untuk ujian, tapi memahaminya membantu mengambil keputusan desain yang tepat.
Client-server
Client (aplikasi pengguna) dan server (penyedia data) dipisah dan berevolusi independen. Konsekuensinya: jangan bocorkan detail implementasi server ke client — nama tabel database atau stack trace tidak boleh muncul di respons API.
Stateless
Setiap request harus memuat semua informasi yang dibutuhkan server. Jangan mengandalkan sesi yang tersimpan di memori server. Praktiknya: kirim token autentikasi di header Authorization pada setiap request. Ini membuat server mudah di-scale horizontal karena request apa pun bisa dilayani instance mana pun.
Cacheable
Respons harus menyatakan dirinya bisa di-cache atau tidak lewat header seperti Cache-Control dan ETag. Aturan praktisnya: GET yang mengembalikan data jarang berubah boleh di-cache; POST tidak. Caching yang benar bisa memangkas beban server secara drastis tanpa mengubah satu baris logika bisnis.
Uniform interface
Ini batasan paling berpengaruh pada desain sehari-hari, dengan empat sub-prinsip:
- Identifikasi resource lewat URL. Setiap resource punya URL unik, misalnya
/products/42. - Manipulasi lewat representasi. Client mengubah resource dengan mengirim representasinya (JSON), bukan dengan perintah prosedural.
- Pesan yang self-descriptive. Method, header, dan status code standar sudah cukup menjelaskan maksud pesan.
- HATEOAS (Hypermedia as the Engine of Application State): respons menyertakan link ke aksi terkait. HATEOAS penuh jarang diimplementasikan di API publik karena menambah kompleksitas — tapi menyertakan link terkait seperti
"self"atau"next"pada respons paginasi adalah praktik yang sehat.
Layered system
Client tidak perlu tahu apakah ia berbicara langsung ke server atau melalui load balancer, CDN, atau API gateway. Desain dengan asumsi ini: jangan mengandalkan IP client untuk logika bisnis, dan pastikan header seperti X-Forwarded-For ditangani di lapisan infrastruktur, bukan di kode aplikasi.
Code on demand (opsional)
Satu-satunya batasan opsional: server boleh mengirim kode yang dieksekusi client (misalnya JavaScript). Hampir tidak relevan untuk REST API modern, jadi cukup ketahui saja.
Mendesain URL dan resource yang konsisten
URL adalah wajah API-mu. Aturan emasnya sederhana: URL menamai resource (kata benda), bukan aksi (kata kerja). Aksi sudah diwakili oleh HTTP method. Begitu aturan ini dipegang, sebagian besar keputusan penamaan jadi otomatis.

Aturan penamaan yang terbukti
- Kata benda jamak, bukan kata kerja.
GET /usersbenar;GET /getUserssalah. Untuk membuat user baru:POST /users, bukanPOST /createUser. - Huruf kecil semua. URL bersifat case-sensitive di sebagian server.
/productsdan/Productsbisa dianggap resource berbeda — hindari kebingungan sejak awal. - Kebab-case untuk kata majemuk.
/order-items, bukan/orderItemsatau/order_items. Pilih satu gaya dan patuhi di seluruh API. - Hierarki untuk relasi.
/users/123/ordersberarti "pesanan milik user 123". Batasi kedalaman maksimal 2–3 level; lebih dari itu pertimbangkan query parameter atau endpoint terpisah. - Query parameter untuk filter, sort, dan search — bukan bagian dari path.
GET /products?category=kopi&sort=pricebenar;GET /products/category/kopi/sort/pricesalah. - Konsisten soal trailing slash. Pilih salah satu (
/usersatau/users/) dan perlakukan yang lain sebagai redirect atau 404 — jangan biarkan keduanya hidup diam-diam sebagai resource berbeda.
| Salah | Benar | Alasan |
|---|---|---|
GET /getAllProducts |
GET /products |
Aksi milik method, bukan URL |
POST /products/delete/42 |
DELETE /products/42 |
Method DELETE sudah menyatakan maksud |
/Users/42 |
/users/42 |
Hindari masalah case-sensitivity |
/products/42/updatePrice |
PATCH /products/42 |
Update parsial lewat body, bukan URL |
/v1/users/123/orders/456/items |
/v1/orders/456/items |
Hierarki terlalu dalam |
Kapan aturan boleh dilanggar
Ada operasi yang memang tidak memetakan rapi ke CRUD, misalnya "kirim ulang email verifikasi" atau "hitung ongkos kirim". Untuk kasus ini, pola yang diterima luas adalah sub-resource aksi: POST /users/123/verification-emails atau POST /shipping-quotes. Bentuknya tetap kata benda, method-nya POST. Yang dihindari adalah RPC murni seperti POST /sendVerificationEmail.
HTTP method dan status code: pakai yang semestinya
HTTP sudah menyediakan kosakata lengkap untuk operasi dan hasil. Memakainya dengan benar membuat API-mu bisa dipahami tanpa dokumentasi.
Method dan sifatnya
| Method | Tujuan | Safe | Idempotent |
|---|---|---|---|
GET |
Membaca resource | Ya | Ya |
POST |
Membuat resource / memicu aksi | Tidak | Tidak |
PUT |
Mengganti seluruh resource | Tidak | Ya |
PATCH |
Mengubah sebagian resource | Tidak | Ya* |
DELETE |
Menghapus resource | Tidak | Ya |
Safe berarti tidak mengubah state server. Idempotent berarti request yang sama diulang hasilnya tetap sama — properti penting untuk retry otomatis saat jaringan bermasalah. PATCH idempotent selama operasinya bersifat "set nilai", bukan "tambah 1".
Praktiknya: PUT /products/42 mengharapkan body berisi seluruh representasi produk; field yang tidak dikirim dianggap dikosongkan. PATCH /products/42 dengan body {"price": 90000} hanya mengubah harga. Dokumentasikan perbedaan ini dengan eksplisit — salah kaprah di sini adalah sumber bug klasik.
Status code yang wajib dikuasai
Jangan kembalikan 200 OK untuk semua respons. Status code adalah bagian dari kontrak:
| Kode | Arti | Kapan dipakai |
|---|---|---|
200 OK |
Berhasil | GET, PUT, PATCH, DELETE yang mengembalikan body |
201 Created |
Resource dibuat | Respons POST yang membuat resource baru; sertakan header Location |
204 No Content |
Berhasil tanpa body | DELETE yang tidak mengembalikan apa-apa |
400 Bad Request |
Request tidak valid | Validasi gagal, JSON malformed |
401 Unauthorized |
Belum terautentikasi | Token hilang, kedaluwarsa, atau salah |
403 Forbidden |
Tidak punya akses | Terautentikasi tapi tidak berhak |
404 Not Found |
Resource tidak ada | ID tidak ditemukan |
409 Conflict |
Konflik state | Email sudah terdaftar, stok tidak cukup |
422 Unprocessable Entity |
Semantik tidak valid | Format benar tapi aturan bisnis dilanggar |
429 Too Many Requests |
Rate limit terlampaui | Sertakan header Retry-After |
500 Internal Server Error |
Kesalahan server | Jangan bocorkan detail internal ke client |
Perbedaan 401 vs 403 sering tertukar: 401 berarti "aku tidak tahu kamu siapa" (masalah autentikasi), 403 berarti "aku tahu kamu siapa, tapi kamu tidak boleh" (masalah otorisasi). Untuk 422 vs 400: 400 untuk request yang bahkan tidak bisa dipahami (JSON rusak), 422 untuk request yang valid secara sintaks tapi melanggar aturan bisnis. Detail lengkapnya ada di dokumentasi status HTTP MDN dan RFC 9110 tentang semantik HTTP.
Versioning, pagination, filtering, dan sorting
Tiga hal ini memisahkan API main-main dari API produksi. Semuanya terlihat sepele sampai API-mu dipakai ribuan client.

Versioning: rencanakan sebelum dibutuhkan
Begitu API dipakai publik, kamu tidak bisa mengubah kontrak seenaknya. Versioning memberi ruang untuk berevolusi tanpa memutus client lama.
| Strategi | Contoh | Kelebihan | Kekurangan |
|---|---|---|---|
| Path URL | /v1/products, /v2/products |
Paling jelas, mudah di-cache dan di-debug | URL berubah antar versi |
| Header | Accept: application/vnd.toko.v2+json |
URL tetap bersih | Sulit dicoba di browser, kurang terlihat |
| Query param | /products?version=2 |
Mudah diimplementasikan | Mengotori query string, aneh di-cache |
Rekomendasi praktis: versioning lewat path URL. Ini pendekatan yang dipakai Stripe, GitHub, dan Twilio karena paling eksplisit — versinya terlihat di log, mudah di-routing di gateway, dan tidak membingungkan developer baru. Mulai dari /v1 sejak hari pertama, bahkan saat belum ada v2. Aturan mainnya: perubahan yang memutus kontrak (menghapus field, mengubah tipe data, mengubah perilaku) wajib naik versi mayor; penambahan field baru yang opsional boleh masuk ke versi yang sama.
Satu catatan penting: jangan pertahankan terlalu banyak versi hidup bersamaan. Umumkan jadwal sunset (misalnya v1 dihentikan 12 bulan setelah v2 rilis) dan kembalikan header Sunset pada respons versi lama agar client tahu batas waktunya.
Pagination: jangan pernah kembalikan "semua data"
Endpoint GET /products tanpa pagination adalah bom waktu. Hari ini datanya 100 baris; tahun depan 10 juta baris dan satu request membuat database bertekuk lutut. Selalu paginasi koleksi, dengan nilai default yang waras (misalnya 20–50 item) dan batas maksimum (misalnya 100).
Dua pendekatan umum:
- Offset-based (
?page=2&limit=20): sederhana dan mendukung lompat ke halaman berapa pun. Kelemahannya, data bisa bergeser bila ada insert/delete di tengah paginasi — item terlewat atau muncul dua kali. - Cursor-based (
?cursor=eyJpZCI6NDJ9&limit=20): stabil untuk dataset besar dan berubah cepat karena penanda berbasis posisi terakhir, bukan nomor halaman. Sedikit lebih rumit di client.
Untuk kebanyakan kasus, offset-based cukup. Untuk feed, timeline, atau tabel jutaan baris, pilih cursor-based. Apa pun pilihannya, respons paginasi harus menyertakan metadata:
{
"success": true,
"data": [
{ "id": 41, "name": "Kopi Robusta 200g", "price": 65000 },
{ "id": 42, "name": "Kopi Arabika 200g", "price": 85000 }
],
"meta": {
"page": 2,
"limit": 20,
"total_items": 1840,
"total_pages": 92
},
"links": {
"self": "/v1/products?page=2&limit=20",
"next": "/v1/products?page=3&limit=20",
"prev": "/v1/products?page=1&limit=20"
},
"error": null
}
Filtering, sorting, dan field selection
Biarkan client meminta tepat apa yang dibutuhkannya lewat query parameter — ini mengurangi jumlah endpoint khusus yang harus kamu buat:
GET /v1/products?category=kopi&min_price=50000&sort=-price,name&fields=id,name,price
Konvensi yang umum: sort=-price berarti descending berdasarkan harga (tanda minus), fields=id,name,price membatasi field yang dikembalikan (sparse fieldsets) untuk menghemat bandwidth — penting untuk aplikasi mobile. Untuk pencarian teks bebas, satu parameter q atau search biasanya cukup: GET /v1/products?q=arabika.
Format respons dan error handling yang konsisten
Konsistensi format adalah pembeda terbesar antara API yang enak dipakai dan yang menyebalkan. Client harus bisa menulis satu fungsi untuk menangani semua respons API-mu.
Envelope respons seragam
Gunakan satu struktur untuk semua respons sukses maupun gagal:
{
"success": true,
"data": { "id": 42, "name": "Kopi Arabika 200g" },
"meta": { "request_id": "req_9f2c1a" },
"error": null
}
request_id terlihat sepele tapi sangat berharga saat debugging: client menyertakannya saat melapor, kamu langsung menemukan jejaknya di log server. Respons yang konsisten juga memudahkan AI agent mem-parsing output API — prinsip yang sejalan dengan praktik prompt engineering yang baik, di mana struktur yang bisa diprediksi membuat model bekerja lebih andal.
Error yang benar-benar membantu
Error yang baik menjawab tiga pertanyaan: apa yang salah, kenapa, dan bagaimana memperbaikinya. Format yang disarankan:
{
"success": false,
"data": null,
"meta": { "request_id": "req_9f2c1a" },
"error": {
"code": "INSUFFICIENT_STOCK",
"message": "Stok produk tidak mencukupi untuk jumlah yang diminta.",
"details": [
{ "field": "quantity", "issue": "Stok tersisa 3, diminta 10." }
]
}
}
Aturannya: code adalah string konstan yang bisa di-switch oleh kode client (OUT_OF_STOCK, VALIDATION_FAILED), message adalah penjelasan untuk manusia, dan details merinci per-field untuk error validasi. Jangan pernah mengembalikan stack trace atau pesan error database mentah ke client — itu membocorkan struktur internal dan tidak membantu siapa pun.
Keamanan: autentikasi, otorisasi, dan rate limiting
API publik tanpa keamanan yang benar adalah undangan terbuka. Pola bakunya sudah mapan — tidak perlu menemukan ulang.
Pilih mekanisme autentikasi yang sesuai
| Mekanisme | Cara kerja | Cocok untuk |
|---|---|---|
| API key | Header X-API-Key: ... |
Integrasi server-to-server sederhana, webhook |
| Bearer token (JWT) | Header Authorization: Bearer ... |
Aplikasi web/mobile dengan login user |
| OAuth 2.0 | Alur otorisasi standar + refresh token | API publik pihak ketiga, login "dengan Google" |
Untuk API internal atau MVP, API key atau JWT cukup. Untuk API yang dipakai developer luar, sediakan OAuth 2.0. Satu aturan keras: token tidak pernah dikirim lewat query string — URL tercatat di log server, histori browser, dan tool analitik. Selalu lewat header.
Otorisasi: autentikasi bukan otorisasi
Fakta bahwa seseorang berhasil login tidak berarti ia boleh mengakses semua data. Terapkan pemeriksaan kepemilikan di setiap endpoint: GET /users/123/orders harus menolak user 456 dengan 403 Forbidden, bukan cuma mengandalkan "URL-nya susah ditebak". Ini disebut Insecure Direct Object Reference (IDOR) dan rutin masuk OWASP API Security Top 10 — daftar risiko keamanan API yang layak dibaca sampai tuntas.
Rate limiting dan kuota
Batasi jumlah request per client (misalnya 1000 request/jam per API key) untuk melindungi server dari bug client maupun penyalahgunaan. Saat limit terlampaui, kembalikan 429 Too Many Requests beserta header Retry-After: 60 agar client tahu kapan boleh mencoba lagi. Sertakan juga header informatif pada respons normal:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997
X-RateLimit-Reset: 1728902400
Daftar periksa keamanan minimum
- HTTPS wajib untuk semua endpoint — tanpa pengecualian, termasuk di dokumentasi contoh.
- Validasi dan sanitasi semua input; jangan percaya data dari client.
- Jangan ekspos ID berurutan bila datanya sensitif — pertimbangkan UUID atau ID acak.
- Set header keamanan standar dan batasi CORS hanya ke origin yang dibutuhkan.
- Log setiap kegagalan autentikasi, tapi jangan log token atau password.
Studi kasus: mendesain API untuk aplikasi e-commerce
Mari terapkan semuanya dalam satu contoh utuh: API untuk toko online "Toko.id" dengan fitur katalog produk, keranjang, checkout, dan riwayat pesanan.
Daftar endpoint
| Method | Endpoint | Deskripsi |
|---|---|---|
GET |
/v1/products |
Daftar produk (paginasi, filter, sort) |
GET |
/v1/products/{id} |
Detail satu produk |
POST |
/v1/carts/items |
Tambah item ke keranjang |
GET |
/v1/carts |
Isi keranjang aktif |
DELETE |
/v1/carts/items/{item_id} |
Hapus item dari keranjang |
POST |
/v1/orders |
Checkout: buat pesanan dari keranjang |
GET |
/v1/orders |
Riwayat pesanan user |
GET |
/v1/orders/{id} |
Detail satu pesanan |
POST |
/v1/orders/{id}/cancellation |
Batalkan pesanan (sub-resource aksi) |
Perhatikan konsistensinya: kata benda jamak di mana-mana, hierarki maksimal dua level, aksi non-CRUD ("cancellation") sebagai sub-resource dengan POST.
Contoh alur checkout
Client membuat pesanan dari keranjang:
POST /v1/orders HTTP/1.1
Host: api.toko.id
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json
{
"shipping_address_id": "addr_8f3k",
"payment_method": "bank_transfer"
}
Respons sukses mengembalikan 201 Created dengan header Location:
HTTP/1.1 201 Created
Content-Type: application/json
Location: /v1/orders/ord_5x2m
{
"success": true,
"data": {
"id": "ord_5x2m",
"status": "awaiting_payment",
"total": 170000,
"expires_at": "2026-10-16T18:46:44+07:00",
"items": [
{ "product_id": 42, "name": "Kopi Arabika 200g", "quantity": 2, "price": 85000 }
]
},
"meta": { "request_id": "req_9f2c1a" },
"error": null
}
Dan saat stok tidak mencukupi, API merespons dengan error yang bisa ditangani kode client secara deterministik:
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"success": false,
"data": null,
"meta": { "request_id": "req_7d1b22" },
"error": {
"code": "INSUFFICIENT_STOCK",
"message": "Stok produk tidak mencukupi untuk jumlah yang diminta.",
"details": [
{ "field": "items[0].quantity", "issue": "Stok tersisa 3, diminta 10." }
]
}
}
Client cukup memeriksa error.code === "INSUFFICIENT_STOCK" untuk menampilkan pesan "stok habis" yang tepat — tanpa parsing string pesan.
Kesalahan umum dalam desain REST API
- Kata kerja di URL.
GET /getUserById?id=5mengabaikan seluruh kosakata HTTP. Perbaiki:GET /users/5. - Semua respons
200 OK. Error yang dibungkus status 200 memaksa client parsing body untuk tahu request gagal — dan merusak caching, monitoring, serta retry otomatis. - Format error berbeda-beda tiap endpoint. Satu endpoint mengembalikan
{"error": "..."}, yang lain{"message": [...]}. Samakan satu envelope untuk seluruh API. - Tidak ada pagination. Endpoint koleksi tanpa
limitakan meledak saat data tumbuh. Tambahkan sejak hari pertama. - Versioning dipikir belakangan. Menambah
/v1setelah API dipakai berarti memigrasikan semua client sekaligus. Mulai berversion sejak awal. - Secret di query string.
?api_key=xxxtercatat di log dan histori browser. Pindahkan ke header. - Mengembalikan terlalu banyak data. Respons user yang menyertakan seluruh riwayat login "siapa tahu butuh" memperlambat mobile dan membocorkan data. Sediakan
fields=untuk seleksi. - Tidak ada dokumentasi. API tanpa OpenAPI/Swagger spec memaksa integrasi lewat trial and error. Tulis spesifikasinya — tool bisa men-generate dokumentasi interaktif dan client SDK dari sana.
- Mengabaikan idempotency pada operasi tulis. Tanpa idempotency key, retry
POST /ordersyang gagal di tengah jalan bisa membuat pesanan ganda. Untuk operasi pembayaran, terima headerIdempotency-Keydan kembalikan respons yang sama untuk key yang sama.
FAQ
Apakah REST API harus selalu memakai JSON?
Tidak wajib, tapi JSON adalah pilihan default yang masuk akal: ringan, didukung semua bahasa pemrograman, dan mudah dibaca manusia. Negosiasikan format lewat header Accept bila ada kebutuhan khusus (misalnya application/xml untuk integrasi legacy), tapi jangan sediakan lima format sekaligus tanpa alasan.
Kapan memakai PUT dan kapan PATCH?
Pakai PUT saat client mengirim representasi lengkap resource pengganti — field yang hilang dianggap dihapus. Pakai PATCH untuk update parsial, misalnya hanya mengganti harga. Kalau ragu dan API-mu sederhana, sediakan PATCH saja dan dokumentasikan dengan jelas.
Bagaimana cara versioning API yang paling aman?
Versioning lewat path URL (/v1/, /v2/) adalah yang paling eksplisit dan mudah dioperasikan: terlihat di log, gampang di-routing, dan jelas bagi developer baru. Umumkan jadwal penghentian versi lama dan sertakan header Sunset agar client bisa bersiap.
Apakah HATEOAS wajib agar bisa disebut REST API?
Secara teori ya menurut definisi Fielding, secara praktik hampir tidak ada API publik besar yang menerapkannya penuh. Yang penting: URL mengidentifikasi resource, method dan status code dipakai sesuai makna, dan pesan bersifat self-descriptive. Menyertakan link self/next/prev pada koleksi sudah merupakan kompromi yang sehat. Referensi yang bagus untuk memahaminya adalah restfulapi.net.
Berapa banyak data yang sebaiknya dikembalikan per halaman?
Default 20–50 item dengan maksimum 100 adalah titik awal yang waras untuk kebanyakan kasus. Untuk dataset besar atau feed real-time, pertimbangkan cursor-based pagination agar tidak ada item yang terlewat saat data berubah.
Kesimpulan
Desain REST API yang baik bermuara pada disiplin terhadap hal-hal dasar: URL menamai resource dengan kata benda, HTTP method dan status code dipakai sesuai maknanya, format respons dan error seragam di seluruh endpoint, serta versioning, pagination, dan keamanan direncanakan sejak hari pertama — bukan ditambal belakangan.
Langkah berikutnya yang paling berdampak: audit satu API yang kamu rawat hari ini terhadap daftar kesalahan umum di atas, lalu perbaiki satu per satu dimulai dari yang paling sering dikeluhkan konsumen. Dan kalau API-mu akan dipakai oleh fitur berbasis LLM — misalnya agent yang memesan lewat API — pelajari juga teknik prompt engineering dari dasar sampai mahir agar instruksi yang kamu berikan ke model sekonsisten API yang kamu rancang. Panduan API tingkat lanjut dari Microsoft tentang desain REST API juga layak dibaca sebagai pembanding.


