Saya sedang membangun API di mana pengguna dapat meminta server untuk melakukan beberapa tindakan dalam satu permintaan HTTP. Hasilnya dikembalikan sebagai array JSON, dengan satu entri per tindakan.
Masing-masing tindakan ini mungkin gagal atau berhasil secara independen satu sama lain. Misalnya, tindakan pertama mungkin berhasil, input ke tindakan kedua mungkin tidak diformat dengan baik dan gagal divalidasi dan tindakan ketiga mungkin menyebabkan kesalahan yang tidak terduga.
Jika ada satu permintaan per tindakan, saya akan mengembalikan kode status masing-masing 200, 422 dan 500. Tetapi sekarang ketika hanya ada satu permintaan, kode status apa yang harus saya kembalikan?
Beberapa opsi:
- Selalu kembalikan 200, dan berikan informasi lebih rinci di badan.
- Mungkin ikuti aturan di atas hanya ketika ada lebih dari satu tindakan dalam permintaan?
- Mungkin mengembalikan 200 jika semua permintaan berhasil, jika tidak 500 (atau kode lain)?
- Cukup gunakan satu permintaan per tindakan, dan terima overhead tambahan.
- Sesuatu yang sama sekali berbeda?
Jawaban:
Jawaban singkat dan langsung
Karena permintaan berbicara tentang mengeksekusi daftar tugas (tugas adalah sumber yang kita bicarakan di sini), maka jika grup tugas telah dipindahkan ke depan untuk dieksekusi (yaitu, terlepas dari hasil eksekusi), maka akan masuk akal bahwa status respons akan
200 OK
. Kalau tidak, jika ada masalah yang akan mencegah eksekusi kelompok tugas, seperti gagal validasi objek tugas , atau beberapa layanan yang diperlukan tidak tersedia misalnya, maka status respons harus menunjukkan kesalahan itu. Melewati itu, ketika pelaksanaan tugas dimulai, mengingat tugas yang harus dilakukan tercantum dalam badan permintaan, maka saya akan berharap bahwa hasil eksekusi akan terdaftar di badan respons.Panjang, jawaban filosofis
Anda mengalami dilema ini karena Anda mengalihkan dari apa HTTP dirancang untuk. Anda tidak berinteraksi untuk mengelola sumber daya, melainkan menggunakannya sebagai cara pemanggilan metode jarak jauh (yang tidak terlalu aneh, namun bekerja dengan buruk tanpa skema yang ditentukan sebelumnya).
Dengan kata-kata di atas, dan tanpa keberanian untuk mengubah jawaban ini menjadi panduan lama, berikut ini adalah skema URI yang sesuai dengan pendekatan manajemen sumber daya:
/tasks
GET
daftar semua tugas, diberi nomor halamanPOST
menambahkan satu tugas/tasks/task/[id]
GET
merespons dengan objek keadaan tugas tunggalDELETE
membatalkan / menghapus tugas/tasks/groups
GET
daftar semua grup tugas, diberi nomor halamanPOST
menambahkan sekelompok tugas/tasks/groups/group/[id]
GET
merespons dengan status grup tugasDELETE
membatalkan / menghapus grup tugasStruktur ini berbicara tentang sumber daya, bukan apa yang harus dilakukan dengan mereka. Apa yang dilakukan dengan sumber daya adalah masalah layanan lain.
Poin penting lain yang harus dibuat adalah disarankan untuk tidak memblokir terlalu lama dalam penangan permintaan HTTP. Sama seperti UI, antarmuka HTTP harus responsif - dalam skala waktu yang beberapa kali lipat lebih lambat (karena lapisan ini berhubungan dengan IO).
Membuat langkah ke arah merancang antarmuka HTTP yang secara ketat mengelola sumber daya mungkin sama sulitnya dengan memindahkan pekerjaan dari utas UI saat tombol diklik. Ini mengharuskan server HTTP berkomunikasi dengan layanan lain untuk menjalankan tugas daripada menjalankannya dalam penangan permintaan. Ini bukan implementasi yang dangkal, ini adalah perubahan arah.
Beberapa contoh bagaimana skema URI akan digunakan
Menjalankan satu tugas dan melacak kemajuan:
POST /tasks
dengan tugas untuk dieksekusiGET /tasks/task/[id]
hingga objek responscompleted
memiliki nilai positif sambil menunjukkan status / kemajuan saat iniMenjalankan satu tugas dan menunggu penyelesaiannya:
POST /tasks
dengan tugas untuk dieksekusiGET /tasks/task/[id]?awaitCompletion=true
hinggacompleted
memiliki nilai positif (kemungkinan memiliki batas waktu, itulah sebabnya ini harus diulang)Menjalankan grup tugas dan melacak kemajuan:
POST /tasks/groups
dengan kelompok tugas untuk dieksekusiGET /tasks/groups/group/[groupId]
sampaicompleted
properti objek respons memiliki nilai, menunjukkan status tugas individu (3 tugas diselesaikan dari 5, misalnya)Meminta eksekusi untuk grup tugas dan menunggu penyelesaiannya:
POST /tasks/groups
dengan kelompok tugas untuk dieksekusiGET /tasks/groups/group/[groupId]?awaitCompletion=true
sampai merespons dengan hasil yang menunjukkan penyelesaian (kemungkinan memiliki batas waktu, itulah sebabnya mengapa harus diulang)sumber
Pilihan saya adalah membagi tugas-tugas ini menjadi permintaan terpisah. Namun, jika terlalu banyak pulang pergi yang memprihatinkan, saya menemukan kode respons HTTP 207 - Multi-Status
Salin / tempel dari tautan ini:
sumber
207
memang terlihat seperti yang diinginkan OP, tapi saya benar-benar ingin menekankan bahwa mungkin ini ide yang buruk untuk memiliki pendekatan multi-permintaan-dalam-satu ini. Jika yang menjadi perhatian adalah kinerja maka Anda harus merancang sistem cloud-scalable secara horizontal (yang merupakan sesuatu yang sangat bagus untuk sistem berbasis HTTP)Meskipun multi-status adalah opsi, saya akan mengembalikan 200 (Semua baik-baik saja) jika semua permintaan berhasil dan kesalahan (500 atau mungkin 207) sebaliknya.
Kasing standar biasanya harus 200 - semuanya berfungsi. Dan klien hanya perlu memeriksa itu. Dan hanya jika kasus kesalahan terjadi Anda dapat mengembalikan 500 (atau 207). Saya pikir 207 adalah pilihan yang valid dalam kasus setidaknya satu kesalahan, tetapi jika Anda melihat seluruh paket sebagai satu transaksi Anda juga dapat mengirim 500. - Klien akan ingin menafsirkan pesan kesalahan dengan cara baik.
Mengapa tidak selalu mengirim 207? - Karena case standar harus mudah dan standar. Sementara kasus luar biasa bisa luar biasa. Seorang klien hanya harus membaca badan respon dan melakukan keputusan rumit lebih lanjut, jika situasi luar biasa menjaminnya.
sumber
Salah satu opsi adalah untuk selalu mengembalikan kode status 200 dan kemudian mengembalikan kesalahan spesifik di badan dokumen JSON Anda. Ini adalah persis bagaimana beberapa API dirancang (mereka selalu mengembalikan kode status 200 dan mengirimkan kesalahan dalam tubuh). Untuk detail lebih lanjut tentang pendekatan yang berbeda, lihat http://archive.oreilly.com/pub/post/restful_error_handling.html
sumber
200
untuk menunjukkan semuanya baik-baik, permintaan diterima dan valid , dan kemudian menggunakan JSON untuk memberikan rincian tentang apa yang terjadi dalam permintaan itu (yaitu hasil dari transaksi).Saya pikir neilsimp1 benar, tetapi saya akan merekomendasikan desain ulang data yang dikirim sedemikian rupa sehingga Anda dapat mengirim
206 - Accepted
dan memproses data nanti. Mungkin dengan panggilan balik.Masalah dengan mencoba mengirim beberapa tindakan dalam satu permintaan adalah fakta bahwa setiap tindakan harus memiliki "status" sendiri
Melihat mengimpor CSV (saya tidak tahu benar-benar tentang OP tapi itu versi sederhana). POST CSV dan dapatkan 206. Kemudian CSV dapat diimpor dan Anda bisa mendapatkan status impor dengan GET (200) terhadap URL yang menunjukkan kesalahan per baris.
Pola yang sama ini dapat diterapkan pada banyak operasi batch
Kode yang menangani POST hanya perlu memverifikasi bahwa format data operasi valid. Kemudian di beberapa waktu kemudian operasi dapat dijalankan. Di pekerja tanah belakang, sehingga Anda dapat skala lebih mudah, misalnya. Kemudian Anda dapat memeriksa status operasi kapan pun Anda mau. Anda dapat menggunakan polling atau menelepon balik, atau stream atau apa pun untuk mengatasi kebutuhan untuk mengetahui kapan satu set operasi selesai.
sumber
Sudah banyak jawaban bagus di sini, tetapi satu aspek tidak ada:
Apa kontrak yang diharapkan klien Anda?
Kode pengembalian HTTP harus menunjukkan setidaknya perbedaan keberhasilan / kegagalan dan dengan demikian memainkan peran "pengecualian orang miskin". Kemudian 200 berarti "kontrak sepenuhnya terpenuhi", dan 4xx atau 5xx menunjukkan kegagalan untuk memenuhi.
Secara naif, saya berharap kontrak permintaan beberapa tindakan Anda adalah "melakukan semua tugas saya", dan jika salah satu dari mereka gagal, maka permintaan itu tidak (sepenuhnya) berhasil. Biasanya, sebagai klien saya akan mengerti 200 sebagai "semuanya baik-baik saja", dan kode dari keluarga 400 dan 500 memaksa saya untuk memikirkan konsekuensi dari kegagalan (sebagian). Jadi, gunakan 200 untuk "semua tugas dilakukan" dan 500 ditambah respons deskriptif jika terjadi kegagalan parsial.
Kontrak hipotetis yang berbeda mungkin "coba lakukan semua tindakan". Maka itu sepenuhnya sesuai dengan kontrak jika (beberapa) tindakan gagal. Jadi, Anda akan selalu mengembalikan 200 plus dokumen hasil di mana Anda menemukan informasi keberhasilan / kegagalan untuk tugas individu.
Jadi, apa kontrak yang ingin Anda ikuti? Keduanya valid, tetapi yang pertama (200 hanya jika semuanya dilakukan) lebih intuitif bagi saya, dan lebih baik sejalan dengan pola perangkat lunak yang khas. Dan untuk sebagian besar (mudah-mudahan) kasus di mana layanan menyelesaikan semua tugas, itu mudah bagi klien untuk mendeteksi kasus itu.
Aspek penting terakhir: Bagaimana Anda mengomunikasikan keputusan kontrak Anda kepada klien Anda? Misalnya di Jawa, saya akan menggunakan nama metode seperti "doAll ()" atau "tryToDoAll ()". Dalam HTTP, Anda dapat memberi nama URL titik akhir sesuai, berharap bahwa pengembang klien Anda melihat, membaca, dan memahami penamaan (saya tidak akan bertaruh untuk itu). Satu lagi alasan untuk memilih kontrak yang paling tidak mengejutkan.
sumber
Menjawab:
Kode status menjelaskan status satu operasi. Karena itu, masuk akal untuk memiliki satu operasi per permintaan.
Beberapa operasi independen melanggar prinsip yang menjadi dasar model respons-permintaan dan kode status. Anda melawan alam.
HTTP / 1.1 dan HTTP / 2 telah membuat overhead permintaan HTTP jauh lebih rendah. Saya memperkirakan ada sangat sedikit situasi di mana permintaan independen batching disarankan.
Yang mengatakan,
(1) Anda dapat membuat banyak modifikasi dengan permintaan PATCH ( RFC 5789 ). Namun, ini mensyaratkan bahwa perubahan untuk tidak independen; mereka diterapkan secara atom (semua atau tidak sama sekali).
(2) Orang lain telah menunjukkan 207 kode Multi-Status. Namun, ini hanya ditentukan untuk WebDAV ( RFC 4918 ), perpanjangan dari HTTP.
Respons 207 WebDAV XML akan seaneh bebek di API non-WebDAV. Jangan lakukan ini.
sumber
Jika Anda benar-benar perlu memiliki beberapa tindakan dalam satu permintaan, mengapa tidak membungkus semua tindakan dalam transaksi di backend? Dengan begitu mereka semua berhasil atau gagal.
Sebagai klien yang menggunakan API, saya dapat menangani kesuksesan atau kegagalan total pada panggilan API. Kesuksesan parsial sulit untuk dihadapi, karena saya harus menangani semua kemungkinan kondisi yang dihasilkan.
sumber