Foto oleh Leef Parks via Pexels

Status code HTTP adalah kode numerik tiga digit yang dikembalikan server untuk menandakan hasil dari sebuah request, dan memilih status code yang tepat adalah bagian penting dari desain API yang baik karena memberikan informasi semantik yang jelas kepada client tanpa perlu membaca body response terlebih dahulu.

Status code dikelompokkan berdasarkan digit pertamanya: 2xx untuk sukses, 3xx untuk redirection, 4xx untuk error di sisi client, dan 5xx untuk error di sisi server, dengan setiap kelompok memiliki kode spesifik yang masing-masing memiliki makna semantik tersendiri.

Artikel ini membahas status code yang paling sering dipakai dalam pengembangan REST API, perbedaan semantik antara kode-kode yang mirip, serta panduan praktis memilih status code yang tepat untuk berbagai skenario umum.

Status Code 2xx untuk Berbagai Jenis Sukses

Berbagai kode sukses untuk konteks berbeda

200 OK -- request berhasil, response berisi data 201 Created -- resource baru berhasil dibuat (untuk POST) 204 No Content -- berhasil, namun tidak ada data dikembalikan (untuk DELETE)
200 OK adalah kode sukses paling umum untuk GET, PUT, atau PATCH, sementara 201 Created lebih tepat dipakai untuk POST yang berhasil membuat resource baru, biasanya disertai header Location yang menunjuk ke resource tersebut. 204 No Content cocok untuk operasi seperti DELETE yang berhasil namun tidak ada data yang perlu dikembalikan dalam body response.

Perbedaan 400, 401, dan 403

Tiga kode error client dengan makna semantik berbeda

400 Bad Request -- request tidak valid, misal format JSON salah 401 Unauthorized -- belum terautentikasi (belum login / token invalid) 403 Forbidden -- sudah terautentikasi, namun TIDAK PUNYA IZIN
Perbedaan 401 dan 403 sering membingungkan: 401 berarti server tidak tahu siapa yang mengirim request (belum terautentikasi atau token tidak valid), sementara 403 berarti server tahu persis siapa pengirimnya namun pengguna tersebut memang tidak diizinkan melakukan aksi tersebut, dua kondisi yang secara semantik sangat berbeda meski keduanya sering disalahartikan sama.

404 vs 422 untuk Error Terkait Data

404 untuk resource tidak ada, 422 untuk data tidak valid

404 Not Found -- resource dengan id tersebut tidak ditemukan 422 Unprocessable Entity -- resource ditemukan/format benar, namun DATA tidak valid secara bisnis
404 Not Found dipakai ketika resource yang diminta memang tidak ada di server, sementara 422 Unprocessable Entity lebih tepat untuk kasus di mana request secara format sudah benar namun melanggar aturan validasi bisnis, seperti mencoba membuat produk dengan harga negatif yang secara teknis valid sebagai JSON namun tidak valid secara bisnis.

500 vs 503 untuk Error Server

500 untuk bug, 503 untuk kondisi sementara server

500 Internal Server Error -- terjadi bug atau exception tak terduga 503 Service Unavailable -- server sedang maintenance atau overload, bersifat SEMENTARA
500 Internal Server Error menandakan terjadi kesalahan yang tidak terduga di kode server, biasanya akibat bug yang perlu diperbaiki developer, sementara 503 Service Unavailable menandakan server sedang dalam kondisi sementara tidak bisa melayani request, misalnya sedang maintenance terjadwal atau kelebihan beban, dan biasanya disertai header Retry-After yang memberitahu client kapan sebaiknya mencoba lagi.

Memilih Status Code yang Tepat untuk Skenario Error

Perbandingan status code untuk empat skenario error yang paling sering tertukar

// 400 Bad Request: input tidak valid dari sisi client POST /api/pesanan { "jumlah": -5 } // Response: 400 { "error": "jumlah harus lebih besar dari 0" } // 401 Unauthorized: token tidak ada / tidak valid GET /api/profil // Response: 401 { "error": "token tidak valid atau kedaluwarsa" } // 403 Forbidden: token valid, tapi tidak punya hak akses DELETE /api/produk/5 // Response: 403 { "error": "role Anda tidak diizinkan menghapus produk" } // 404 Not Found: resource memang tidak ada GET /api/produk/9999 // Response: 404 { "error": "produk dengan id 9999 tidak ditemukan" }

Banyak API pemula hanya membedakan sukses (200) dan gagal (500), padahal HTTP menyediakan status code yang jauh lebih spesifik untuk menjelaskan jenis kegagalan. 401 Unauthorized berarti identitas pemanggil belum terverifikasi, sedangkan 403 Forbidden berarti identitas sudah dikenali namun tidak memiliki izin untuk aksi tersebut; mencampuradukkan keduanya membuat client sulit menentukan apakah perlu login ulang atau meminta akses tambahan.

400 Bad Request dipakai ketika kesalahan ada pada data yang dikirim client, seperti format JSON yang salah atau nilai yang melanggar validasi bisnis, dan harus dibedakan dari 404 Not Found yang berarti resource yang diminta memang tidak eksis di server. Pemilihan status code yang tepat memungkinkan client menulis logika penanganan error yang spesifik, misalnya menampilkan form validasi untuk 400 dan halaman 'tidak ditemukan' untuk 404, tanpa harus mem-parsing pesan error secara manual.

Konsistensi status code di seluruh endpoint juga penting untuk dokumentasi API dan pengujian otomatis, karena tim QA dan tim frontend biasanya menulis assertion berdasarkan kode numerik tersebut. Ketika sebuah tim mengubah arti 403 menjadi error validasi hanya pada satu endpoint tertentu, seluruh kontrak yang sudah disepakati sebelumnya menjadi tidak dapat diandalkan oleh konsumen API lain.

Redirect 3xx dan Caching Response dengan 304 Not Modified

Kombinasi 301 untuk pemindahan resource dan 304 untuk caching kondisional

// 301: resource dipindah permanen ke URL baru GET /api/pelanggan/lama // Response: 301 Moved Permanently, Location: /api/pelanggan/baru // Permintaan pertama menyertakan ETag pada response GET /api/produk/5 // Response: 200, ETag: "a1b2c3d4" // Permintaan berikutnya mengirim If-None-Match dengan ETag tersebut GET /api/produk/5 If-None-Match: "a1b2c3d4" // Jika data belum berubah: // Response: 304 Not Modified (tanpa body, hemat bandwidth)

Status code 3xx sering diabaikan dalam desain REST API karena dianggap hanya relevan untuk halaman web, padahal 301 Moved Permanently dan 302 Found tetap berguna ketika struktur endpoint berubah dan API perlu mengarahkan client lama ke lokasi baru tanpa langsung mengembalikan error. 301 menandakan perpindahan permanen sehingga client dan browser bisa memperbarui bookmark atau cache URL, sedangkan 302 dipakai untuk pengalihan sementara yang suatu saat bisa kembali ke URL semula. Penggunaan redirect yang konsisten juga menjaga dokumentasi API tetap akurat ketika struktur endpoint berubah seiring waktu.

304 Not Modified bekerja dengan mekanisme caching kondisional menggunakan header ETag atau Last-Modified. Server menghasilkan ETag berupa hash dari konten response, dan client menyimpan nilai tersebut untuk disertakan pada header If-None-Match di request berikutnya. Jika data di server belum berubah sejak ETag tersebut dihasilkan, server cukup membalas 304 tanpa body, sehingga client tahu untuk memakai data yang sudah tersimpan di cache lokal. Header Last-Modified bisa dipakai sebagai alternatif ETag ketika menghitung hash konten dianggap terlalu mahal untuk resource berukuran besar.

Penerapan 304 sangat membantu pada endpoint dengan data yang jarang berubah namun sering diakses, seperti daftar kategori produk atau konfigurasi aplikasi, karena mengurangi beban transfer data secara signifikan dibanding selalu mengirim ulang body JSON yang sama. Namun mekanisme ini menambah kompleksitas implementasi karena server harus konsisten menghitung dan memvalidasi ETag setiap kali data resource berubah, bukan sekadar menghasilkan nilai acak. Tim perlu memastikan proses update data juga memperbarui ETag secara bersamaan, agar client tidak menerima 304 untuk data yang sebenarnya sudah berubah.

Menangani Rate Limiting dengan Status 429 Too Many Requests

Response 429 lengkap dengan header pemberitahuan batas

// Client mengirim request melebihi batas yang diizinkan GET /api/produk // Response: 429 Too Many Requests // Headers: // Retry-After: 30 // X-RateLimit-Limit: 100 // X-RateLimit-Remaining: 0 { "error": "Batas permintaan tercapai, coba lagi dalam 30 detik" }

Status code 429 Too Many Requests dikirim server ketika sebuah client telah melampaui jumlah permintaan yang diizinkan dalam periode waktu tertentu. Header pendukung seperti X-RateLimit-Limit dan X-RateLimit-Remaining memberi informasi kepada client berapa sisa kuota yang masih tersedia, sehingga client bisa mengatur kecepatan pengiriman request sebelum benar-benar diblokir.

Header Retry-After memberi tahu secara eksplisit berapa detik lagi client boleh mencoba kembali, dan client yang baik seharusnya menunggu sesuai nilai tersebut daripada langsung mencoba ulang tanpa jeda. Rate limiting biasanya diterapkan per API key atau per alamat IP untuk melindungi server dari lonjakan traffic berlebihan, baik yang disengaja maupun akibat bug pada sisi client yang memanggil endpoint secara berulang tanpa kontrol.

Kesalahan Umum yang Sering Terjadi

Selalu Mengembalikan 200 OK Meski Terjadi Error

Mengembalikan status 200 OK dengan field 'success: false' di body response alih-alih status code error yang sesuai membuat client sulit menangani error secara konsisten menggunakan mekanisme error handling HTTP standar seperti interceptor.

Menggunakan 404 untuk Semua Jenis Error

Mengembalikan 404 untuk error yang sebenarnya bukan masalah resource tidak ditemukan, seperti validasi gagal yang seharusnya 400 atau 422, membuat client API kesulitan membedakan akar masalah sebenarnya dari request yang gagal.

Mencampur 401 dan 403 Secara Sembarangan

Mengembalikan 401 untuk kasus yang sebenarnya otorisasi (pengguna sudah login namun tidak punya izin) membuat client API salah mengambil tindakan, misalnya mencoba refresh token padahal masalahnya adalah kurangnya hak akses, bukan token yang invalid.

Kapan Pendekatan Ini Tidak Cocok Dipakai

Mengikuti semantik status code HTTP secara ketat membutuhkan pemahaman mendalam tentang setiap kode dan kapan tepat dipakai, namun memberikan API yang jauh lebih predictable dan mudah diintegrasikan oleh client dari berbagai platform dan bahasa pemrograman.

Beberapa API yang lebih sederhana memilih hanya memakai subset kecil status code (200, 400, 404, 500) demi kesederhanaan, mengorbankan sedikit presisi semantik namun mengurangi kompleksitas penanganan error di sisi client yang mungkin tidak membutuhkan granularitas setinggi itu.

Ringkasan

Memilih status code HTTP yang tepat memberikan informasi semantik yang jelas kepada client tanpa perlu membaca body response, mulai dari perbedaan 401 dan 403 hingga 404 dan 422. Pahami makna setiap kode dengan baik dan terapkan secara konsisten di seluruh API untuk pengalaman integrasi yang lebih baik bagi konsumen API.

Seri Belajar REST API & Clean Architecture:

← Sebelumnya: Prinsip Dasar REST API dan HTTP Method

→ Selanjutnya: Desain Endpoint REST API yang Baik