HTTP status code adalah angka tiga digit yang dikirim server untuk memberi tahu hasil sebuah request. Digit pertamanya menunjukkan kelompok: 1xx informasi, 2xx sukses, 3xx pengalihan, 4xx kesalahan dari sisi klien, dan 5xx kesalahan dari sisi server. Memahami kode yang tepat membuat API Anda lebih mudah dipakai dan error lebih cepat dilacak.
Artikel ini membahas kode-kode yang paling sering Anda temui, termasuk 419 yang khas Laravel, lengkap dengan tabel ringkas dan panduan kode mana yang sebaiknya dikembalikan oleh REST API. Jika Anda belum terlalu paham alur request dan response, baca dulu cara kerja HTTP dan HTTPS.
Lima kelompok status code
| Kelompok | Arti | Siapa yang perlu bertindak |
|---|---|---|
| 1xx | Informasi sementara, request masih diproses | Biasanya ditangani otomatis oleh browser/klien |
| 2xx | Request berhasil | Tidak ada; proses data respons |
| 3xx | Sumber daya ada di tempat lain atau tidak berubah | Klien mengikuti URL baru atau memakai cache |
| 4xx | Request salah atau tidak diizinkan | Klien harus memperbaiki request |
| 5xx | Server gagal memproses request yang valid | Developer/admin server |
Pembagian ini penting untuk debugging. Jika Anda melihat 4xx, periksa dulu apa yang dikirim klien. Jika melihat 5xx, buka log server. Spesifikasi resmi semantik HTTP saat ini ada di RFC 9110.
Tabel ringkas kode yang paling penting
| Kode | Nama | Kapan muncul |
|---|---|---|
| 200 | OK | Request sukses dan ada body respons |
| 201 | Created | Data baru berhasil dibuat |
| 204 | No Content | Sukses tanpa body (misal setelah hapus) |
| 301 | Moved Permanently | URL pindah permanen |
| 302 | Found | Pengalihan sementara |
| 304 | Not Modified | Cache klien masih valid |
| 307 / 308 | Temporary / Permanent Redirect | Pengalihan yang mempertahankan method dan body |
| 400 | Bad Request | Format request rusak |
| 401 | Unauthorized | Belum login / token tidak valid |
| 403 | Forbidden | Sudah login tetapi tidak berhak |
| 404 | Not Found | Sumber daya tidak ada |
| 405 | Method Not Allowed | Method HTTP tidak didukung di URL itu |
| 409 | Conflict | Bentrok dengan kondisi data saat ini |
| 419 | Page Expired (Laravel) | Token CSRF tidak cocok / sesi habis |
| 422 | Unprocessable Content | Validasi gagal |
| 429 | Too Many Requests | Terkena rate limit |
| 500 | Internal Server Error | Error tak terduga di aplikasi |
| 502 | Bad Gateway | Proxy menerima respons tidak valid dari upstream |
| 503 | Service Unavailable | Server sedang maintenance/kewalahan |
| 504 | Gateway Timeout | Upstream terlalu lama merespons |
1xx: informasi
Kode 1xx jarang Anda tangani langsung. 100 Continue memberi tahu klien bahwa ia boleh melanjutkan mengirim body besar. 101 Switching Protocols muncul saat koneksi di-upgrade, misalnya ke WebSocket. 103 Early Hints memungkinkan server memberi petunjuk resource (CSS, font) yang bisa dimuat lebih awal sebelum respons final siap.
2xx: sukses
200 OK
Respons sukses umum. Cocok untuk GET yang mengembalikan data, serta PUT/PATCH yang mengembalikan data hasil update.
201 Created
Gunakan setelah POST berhasil membuat data baru. Idealnya sertakan header Location berisi URL data baru, dan kembalikan representasi data tersebut di body. Di Laravel, API Resource yang membungkus model yang baru dibuat otomatis memakai status 201.
204 No Content
Sukses, tetapi tidak ada body. Cocok untuk DELETE atau update yang tidak perlu mengembalikan data. Jangan mengirim body JSON bersama 204; banyak klien akan mengabaikannya.
// Laravel
return response()->json($order, 201); // dibuat
return response()->noContent(); // 204
3xx: pengalihan dan cache
301 vs 302
301 Moved Permanently berarti URL lama sudah pindah selamanya. Mesin pencari akan memindahkan sinyal peringkat ke URL baru, dan browser bisa menyimpan pengalihan ini di cache. Pakai untuk migrasi domain, perubahan slug, atau memaksa HTTPS. 302 Found berarti pengalihan sementara, misalnya ke halaman login lalu kembali lagi. Fungsi redirect() di Laravel default memakai 302.
304 Not Modified
Muncul ketika browser bertanya "apakah resource ini berubah?" dengan header If-None-Match (ETag) atau If-Modified-Since, dan server menjawab tidak. Body tidak dikirim ulang, sehingga hemat bandwidth. Ini bukan error.
307 dan 308
Secara historis, banyak klien mengubah POST menjadi GET saat mengikuti 301/302. 307 Temporary Redirect dan 308 Permanent Redirect dibuat agar method dan body tetap sama. Jika Anda mengalihkan endpoint API yang menerima POST, pakai 307 atau 308. Ada juga 303 See Other, yang sengaja mengarahkan klien melakukan GET ke URL lain, misalnya setelah form disubmit.
4xx: kesalahan dari sisi klien
400 Bad Request
Request tidak bisa dipahami: JSON rusak, parameter wajib berformat salah, atau header tidak valid. Untuk validasi isi data (misalnya email tidak valid), banyak framework termasuk Laravel memilih 422.
401 vs 403: yang paling sering tertukar
Meski namanya "Unauthorized", 401 sebenarnya berarti belum terautentikasi: server tidak tahu siapa Anda, atau token yang dikirim tidak valid/kedaluwarsa. Solusinya adalah login atau mengirim kredensial yang benar. Menurut spesifikasi, respons 401 wajib menyertakan header WWW-Authenticate.
403 Forbidden berarti server tahu siapa Anda, tetapi Anda tidak berhak. Login ulang tidak akan membantu. Contohnya pengguna biasa yang mengakses halaman admin.
// Laravel
abort(403); // tidak berhak
$this->authorize('update', $post); // 403 otomatis bila policy menolak
// middleware auth:sanctum -> 401 {"message":"Unauthenticated."} untuk request JSON
Catatan keamanan: untuk resource privat, sebagian aplikasi sengaja mengembalikan 404 alih-alih 403 agar keberadaan data tidak terungkap.
404 Not Found
URL atau data tidak ditemukan. Di Laravel, findOrFail() dan route model binding otomatis menghasilkan 404. Halaman yang dihapus permanen boleh memakai 410 Gone agar mesin pencari lebih cepat mengeluarkannya dari indeks.
405 Method Not Allowed
URL-nya ada, tetapi method-nya salah, misalnya mengirim GET ke route yang hanya menerima POST. Di Laravel penyebab umumnya adalah form tanpa @method('PUT'), atau route cache yang belum diperbarui setelah menambah route.
409 Conflict
Request valid secara format, tetapi bentrok dengan kondisi data saat ini: username sudah dipakai, stok sudah habis saat checkout, atau versi data yang diedit sudah diubah orang lain (optimistic locking).
419 Page Expired (khusus Laravel)
Kode 419 tidak ada di standar HTTP; Laravel memakainya untuk TokenMismatchException, yaitu token CSRF tidak cocok. Penyebab yang paling umum:
- Form tidak menyertakan
@csrf. - Sesi kedaluwarsa karena halaman dibuka terlalu lama.
- Request AJAX tidak mengirim header
X-CSRF-TOKEN/X-XSRF-TOKEN. - Konfigurasi cookie sesi salah (
SESSION_DOMAIN,SESSION_SECURE_COOKIEdi HTTP biasa), sehingga sesi tidak pernah tersimpan.
Pembahasan error Laravel lainnya ada di kumpulan solusi error Laravel.
Berlangganan gratis. Artikel & tutorial coding terbaru langsung ke email kamu. Tanpa spam.
422 Unprocessable Content
Format request benar, tetapi isinya gagal validasi. Laravel mengembalikan 422 secara otomatis ketika validasi gagal pada request JSON, dengan struktur seperti ini:
{
"message": "The email field is required. (and 1 more error)",
"errors": {
"email": ["The email field is required."],
"password": ["The password field must be at least 8 characters."]
}
}
429 Too Many Requests
Klien melebihi batas rate limit. Sertakan header Retry-After agar klien tahu kapan boleh mencoba lagi. Middleware throttle Laravel sudah melakukannya.
Route::middleware('throttle:60,1')->group(function () {
// maksimal 60 request per menit
});
5xx: kesalahan dari sisi server
500 Internal Server Error
Ada exception yang tidak tertangani. Jangan pernah menampilkan stack trace ke publik; pastikan APP_DEBUG=false di produksi, lalu cek storage/logs/laravel.log. Penyebab umum di Laravel: permission folder storage, .env belum diisi, atau APP_KEY kosong.
502 Bad Gateway
Proxy atau web server (Nginx, Cloudflare) tidak mendapat respons valid dari aplikasi di belakangnya. Pada setup Nginx + PHP-FPM, penyebab tersering adalah PHP-FPM mati, path socket di konfigurasi Nginx salah, atau proses PHP crash. Langkah pengecekan dibahas di deploy Laravel ke VPS Ubuntu dengan Nginx.
503 Service Unavailable
Server sementara tidak bisa melayani, karena maintenance atau kelebihan beban. php artisan down membuat Laravel mengembalikan 503. Untuk maintenance terencana, sertakan Retry-After; Google memahami 503 sebagai gangguan sementara, berbeda dengan 404.
504 Gateway Timeout
Proxy menunggu terlalu lama. Biasanya karena query lambat, panggilan API eksternal yang menggantung, atau proses berat (ekspor, kirim email massal) yang dijalankan langsung di request. Solusi jangka panjang: pindahkan ke queue, bukan sekadar menaikkan timeout.
Kode apa yang dikembalikan REST API?
| Operasi | Sukses | Gagal umum |
|---|---|---|
GET /orders | 200 | 401, 403 |
GET /orders/{id} | 200 | 404 |
POST /orders | 201 + Location | 422, 409 |
PUT/PATCH /orders/{id} | 200 (dengan data) atau 204 | 404, 422, 409 |
DELETE /orders/{id} | 204 | 404, 403 |
| Proses async (antrian) | 202 Accepted | 429 |
Prinsip pentingnya: status code harus jujur. Pola "selalu 200, error ditulis di body" ({"success": false}) menyulitkan klien, monitoring, dan cache, karena semua alat HTTP menganggap request tersebut berhasil. Kembalikan kode yang sesuai, lalu sertakan body error yang konsisten. Dasar-dasar desain API dibahas di apa itu REST API.
Kesalahan umum
- Memakai 401 untuk "tidak berhak" padahal pengguna sudah login (seharusnya 403).
- Mengembalikan 200 dengan pesan error di body.
- Mengembalikan 500 untuk validasi gagal karena exception tidak ditangkap.
- Memakai 302 untuk pindah domain permanen, sehingga sinyal SEO tidak berpindah dengan jelas.
- Menaikkan timeout Nginx untuk menutupi 504 alih-alih memindahkan proses berat ke queue.
Checklist
- 2xx hanya untuk sukses yang sebenarnya; 201 untuk create, 204 untuk tanpa body.
- 401 = belum login, 403 = tidak berhak, 404 = tidak ada.
- 422 untuk validasi, 409 untuk konflik data, 429 dengan
Retry-After. - 301/308 untuk pindah permanen, 302/307 untuk sementara.
- Produksi:
APP_DEBUG=false, log 5xx dipantau.
FAQ
Apa beda 401 dan 403?
401 berarti server belum mengenali Anda (belum login atau token tidak valid). 403 berarti server mengenali Anda tetapi menolak akses. Pada 401, login bisa menyelesaikan masalah; pada 403 tidak.
Kenapa Laravel memakai 419, bukan kode standar?
Laravel memilih 419 untuk membedakan kegagalan CSRF/sesi kedaluwarsa dari error lain. Kode ini tidak terdaftar di standar HTTP, tetapi klien tetap memperlakukannya sebagai 4xx.
Apakah 304 berarti ada error?
Bukan. 304 berarti browser boleh memakai salinan cache-nya karena resource belum berubah. Ini justru tanda caching berjalan baik.
Kapan memakai 400 dan kapan 422?
Gunakan 400 jika request tidak bisa diparse sama sekali (JSON rusak, header salah). Gunakan 422 jika request bisa dibaca tetapi isinya tidak memenuhi aturan validasi. Yang penting konsisten di seluruh API.
Apakah 502 dan 504 berasal dari kode saya?
Kedua kode itu dibuat oleh proxy atau web server, bukan oleh Laravel. Namun penyebabnya sering ada di aplikasi: PHP-FPM crash (502) atau proses yang terlalu lama (504). Periksa log Nginx dan log PHP-FPM bersama log Laravel.