Haruskah saya mengembalikan status HTTP 400 (Permintaan Buruk) jika parameter secara sintaksis benar, tetapi melanggar aturan bisnis?

56

Katakanlah bahwa saya memiliki titik akhir REST yang menggunakan integer sebagai parameter:

/makeWaffles?numberOfWaffles=3

Dalam hal ini, saya ingin angka menjadi positif karena saya tidak dapat membuat jumlah negatif wafel (dan meminta 0 wafel adalah buang-buang waktu). Jadi saya ingin menolak permintaan yang tidak mengandung bilangan bulat positif. Saya juga ingin menolak permintaan yang melebihi beberapa bilangan bulat maksimum (katakanlah untuk saat ini adalah MAX_INTEGER).

Jika seseorang meminta jumlah wafel yang tidak positif, haruskah saya mengembalikan status HTTP 400 (Permintaan Buruk)? Pikiran awal saya adalah ya: itu bukan nomor yang valid bagi saya untuk menyelesaikan permintaan. Namun, RFC tidak menyebutkan aturan bisnis sebagai alasan untuk membuangnya:

Kode status 400 (Permintaan Buruk) menunjukkan bahwa server tidak dapat atau tidak akan memproses permintaan karena sesuatu yang dianggap sebagai kesalahan klien (misalnya, sintaks permintaan salah bentuk, pembingkaian pesan permintaan tidak valid, atau perutean permintaan yang menipu).

Aturan bisnis tidak termasuk dalam salah satu dari tiga contoh itu. Secara sintaksis benar, dibingkai dengan benar, dan itu bukan perutean permintaan yang menipu.

Jadi, haruskah saya mengembalikan status HTTP 400 (Permintaan Buruk) jika parameter secara sintaksis benar, tetapi melanggar aturan bisnis? Atau apakah ada status yang lebih tepat untuk dikembalikan?

Thunderforge
sumber

Jawaban:

38

Ini adalah pertanyaan yang bagus, dan masih sangat relevan mengingat konteks historis (dan definisi yang tampaknya kontradiktif) dari kode pengembalian HTTP. Bahkan di antara jawaban atas pertanyaan ini ada definisi yang bertentangan. Ini bisa diklarifikasi dengan bergerak secara kronologis.

RFC 2616 (Juni 1999)

10.4.1 400 Permintaan Buruk

Permintaan tidak dapat dipahami oleh server karena sintaksis yang salah. Klien TIDAK HARUS mengulangi permintaan tanpa modifikasi.

Pada RFC ini, kode status ini khusus diterapkan hanya untuk permintaan yang secara sintaktis tidak valid. Ada celah dalam kode status untuk validasi semantik. Jadi, ketika RFC 4918 muncul, kode baru lahir.

RFC 4918 (Juni 2007)

11.2. 422 Entitas yang Tidak Dapat Diproses

Kode status 422 (Entitas yang Tidak Dapat Diproses) berarti server memahami jenis konten entitas permintaan (oleh karena itu kode status 415 (Jenis Media yang Tidak Didukung) tidak pantas), dan sintaks entitas permintaan benar (dengan demikian 400 (Permintaan Buruk) ) kode status tidak pantas) tetapi tidak dapat memproses instruksi yang terkandung. Sebagai contoh, kondisi kesalahan ini dapat terjadi jika badan permintaan XML berisi formulasi XML yang baik (yaitu, benar secara sintaksis), tetapi secara semestinya salah.

422 Entitas yang tidak dapat diproses dibuat untuk mengisi celah validasi semantik dalam spesifikasi asli kode status 4xx. Namun, RFC lain yang relevan muncul pada tahun 2014 yang menggeneralisasi 400 menjadi tidak lagi spesifik untuk sintaksis .

RFC 7231 (Juni 2014, secara eksplisit obsoletes RFC 2616)

6.5.1. 400 permintaan Buruk

Kode status 400 (Permintaan Buruk) menunjukkan bahwa server tidak dapat atau tidak akan memproses permintaan karena sesuatu yang dianggap sebagai kesalahan klien (misalnya, sintaks permintaan salah bentuk, pembingkaian pesan permintaan tidak valid, atau perutean permintaan yang menipu).

Perhatikan bahwa deskripsi 422 mengatakan bahwa alasan 400 tidak pantas adalah karena 400 (per RFC 2616) harus dikembalikan hanya untuk sintaks permintaan yang buruk. Namun, pada RFC 7231, definisi kesalahan-sintaks yang ketat tidak lagi berlaku untuk 400 .

Kembali ke pertanyaan yang ada: Sementara 422 secara teknis lebih spesifik, mengingat konteks ini, saya bisa melihat 400 atau 422 digunakan untuk validasi semantik parameter API. Saya ragu-ragu untuk menggunakan 422 di API saya sendiri karena definisi 422 secara teknis sudah ketinggalan zaman pada saat ini (meskipun saya tidak tahu apakah itu diakui secara resmi di mana saja). Artikel yang dirujuk dalam jawaban Fran yang mendorong penggunaan 422 ditulis pada tahun 2012, dua tahun sebelum RFC 7231 mengklarifikasi HTTP 400. Pastikan untuk menstandarisasi satu atau yang lain.

Kyle McVay
sumber
42

Saya membaca jawaban pertama dan tidak terlalu setuju dengan itu karena, setidaknya dalam bacaan saya, permintaan yang buruk (400) berarti, "Saya bahkan tidak bisa menangani permintaan Anda karena ada sesuatu yang secara fundamental salah." Dan saya menemukan posting ini yang membuat kasus untuk mengembalikan 422.

dari IETF

422 Entitas yang Tidak Dapat Diproses (WebDAV; RFC 4918) Permintaan dibuat dengan baik tetapi tidak dapat diikuti karena kesalahan semantik

Ini sepertinya respons yang lebih tepat karena permintaan Anda dibuat dengan baik, tetapi tidak lulus aturan validasi Anda.

Fran
sumber
5
Aku pernah mendengarnya digambarkan sebagai "400 berarti sintaksis buruk, 422 berarti semantik buruk."
cbojar
33
Semua kode x00 adalah "tangkap semua" kode umum. A 400 tidak pantas , hanya kurang spesifik .
Jack
1
Jawaban yang baik, tapi ansewer yang diberikan oleh @GoFree lebih masuk akal bagi saya.
Ewerton
2
Ada kasus yang sangat kuat untuk mengembalikan kode yang diketahui semua orang. Benar-benar semua orang perlu mencari 422, dan saya berani bertaruh bahwa sebagian besar masih tidak akan tahu apa yang harus dilakukan.
sylvanaar
8

Ya, input yang tidak mengikuti kontrak tersirat dari titik akhir adalah "sesuatu yang dianggap sebagai kesalahan klien", dan harus mengembalikan 400.

Pengecualian untuk ini adalah jika aturan bisnis terkait keamanan (maka 401 Unauthorizedatau 403 Forbiddenakan lebih baik). Atau, jika mengirim 400 akan membocorkan informasi tentang keberadaan sesuatu, dan kemudian 404 Not Foundmungkin lebih tepat.

Telastyn
sumber
8

Tidak, seharusnya tidak. Kode HTTP dimaksudkan untuk lapisan HTTP aplikasi Anda. Aturan bisnis adalah lapisan yang sepenuhnya berbeda dan khusus untuk aplikasi, jadi Anda perlu membuat "protokol" sendiri.

Bayangkan kiamat terjadi dan Anda harus beralih dari protokol HTTP ke menggunakan Merpati. Merpati tidak memiliki kode pengembalian, jadi Anda perlu mengubah lapisan bisnis Anda untuk mengakomodasi itu. Tetapi bisnis Anda belum benar-benar berubah sehingga Anda tidak perlu mengubah lapisan bisnis. Ini menunjukkan hubungan yang erat antara dua lapisan (transportasi dan bisnis).

Kembali ke pertanyaan: Apa yang harus Anda lakukan adalah mengembalikan "200 OK" dengan badan yang menjelaskan apa yang terjadi dengan permintaan tersebut. Spesifikasi jelas mengatakan:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1 .

200 OK

Permintaan telah berhasil. The informasi kembali dengan respon tergantung pada metode yang digunakan dalam permintaan , misalnya

POST entitas yang menggambarkan atau mengandung hasil tindakan;

Apakah permintaan HTTP Anda berhasil? Ya, server web tahu apa yang harus dilakukan dengan permintaan itu (mis. Meneruskannya ke bagian server aplikasi Anda). Server web kemudian meneruskan permintaan ini ke bagian server aplikasi Anda, yang mengambil data POSTed, memprosesnya (memvalidasi mereka dalam kasus Anda) dan mengembalikan jawaban normal (di badan respons HTTP) ke bagian klien dari aplikasi Anda . Jawaban dari bagian server aplikasi ini dapat berupa "Hebat, data yang Anda kirimi saya valid" atau "Maaf, data yang Anda kirim tidak valid". Dan itu tergantung pada bagian aplikasi klien Anda untuk memahami apa artinya jawabannya.

PS: "400 Bad Request" artinya, bahwa server web tidak mengerti apa yang Anda inginkan darinya. Ini berarti bahwa bagian server Anda dari aplikasi Anda bahkan tidak menerima permintaan. Atau setidaknya itulah artinya :-)

EDIT : Saya baru sadar, bahwa Anda melakukan permintaan GET, bukan POST. Ini adalah ide yang buruk karena GET tidak boleh mengubah keadaan aplikasi. GET seharusnya hanya mengambil data dari server. Tetapi dalam permintaan Anda, Anda benar-benar mengubah keadaan aplikasi, jadi Anda harus benar-benar menggunakan POST.

GoFree
sumber
1
Ya, mengembalikan 404 dalam kasus itu baik-baik saja. Saya tidak mengatakan bahwa server harus selalu mengirim 200 OK dengan penjelasan di badan.
GoFree
Penjelasan yang lebih baik saya lihat sejauh ini. Saya memiliki pertanyaan yang sama dan sepertinya semua kata berbeda dari saya dan Anda @Gratis
Ewerton
@GoFree Ini adalah jawaban yang sangat bagus untuk memikirkan kembali Desain API. Tapi bukankah itu masalahnya, bahwa kita menggunakan HTTP dan kode responsnya sebagai bagian dari lapisan aturan bisnis ketika kita menggunakan REST API?
Thomas Lauria
1
@ Thomas Lauria Saya belum melihat implementasi yang tepat dari RESTFUL API. Namun, REST API adalah kata kunci hari ini sehingga setiap perusahaan harus menggunakannya (kata, bukan teknologi) tanpa benar-benar memahami konsep di baliknya. Jadi ya, itu digunakan dengan cara yang salah di mana-mana. Apa yang biasanya dibuat oleh pemrogram bukanlah REST API, tetapi HTTP API, atau API OVER HTTP. Sebenarnya salah satu dari beberapa implementasi RESTFUL yang bagus adalah HTTP itu sendiri :)
GoFree
1
Menggunakan 200-OK sangat logis jika aplikasi menyertakan bidang "kesalahan" di badan respons untuk menjelaskan kesalahan tingkat bisnis seperti nilai input yang terlalu tinggi atau terlalu rendah atau hilang, produk kehabisan stok, dll.
Roland
-3

Tidak yakin bahwa semua akan setuju, tetapi kami menggunakan 409 - Konflik. Banyak negara bagian 409 lebih merupakan konflik dengan keadaan sistem, tetapi kami menerima interpretasi bahwa konflik nilai data yang berada di luar rentang yang diterima dapat diperbaiki oleh pemohon dan penggunaan yang dapat diterima dari 409. 422 Saya pikir akan masuk akal sebagai permintaan terbentuk dengan benar tetapi tidak dapat diproses seperti yang diminta. Namun saya berpendapat jika Anda tidak ingin menerapkan sejumlah balasan, hanya memberikan 400 masih dapat diterima.

dlb
sumber
5
409 berarti "negara tempat Anda mencoba memasukkan ini bertentangan dengan keadaan klien lain mencoba memasukkan ini", itu untuk memblokir penulisan bersamaan (menggunakan ETags, misalnya)
Jack