Untuk memasukkan ID sumber daya dalam muatan atau berasal dari URI

13

Mendesain API, kami menemukan pertanyaan apakah muatan PUT harus berisi ID sumber daya yang diperbarui.

Inilah yang saat ini kami miliki:

PUT /users/123 Payload: {name: "Adrian"}

Kode rute kami mengekstraksi ID dari URI dan melanjutkan pembaruan.

Pengguna pertama API kami mempertanyakan mengapa kami tidak mengizinkan ID dalam muatan:

PUT /users/123 Payload: {id: 123, name: "Adrian"}

Alasan kami tidak mengizinkannya adalah karena ID digandakan, dalam payload dan URI.

Memikirkan hal ini lagi, kami menggabungkan sumber daya ke URI.

Jika URI tidak memiliki ID, payload perlu diubah:

PUT /no/id/here Payload: {name: "Adrian"} < What user???

Apakah ada alasan untuk tidak melakukannya?

Adrian Lynch
sumber

Jawaban:

14

Anda seharusnya memasangkan Uniform Resource Identifier ke sumber daya .

Ketika REST diimplementasikan dengan HTTP, Anda menggunakan GET untuk mengambil nilai sumber daya saat ini dan PUT untuk menetapkan nilai baru. GET tidak memiliki muatan, sehingga sumber daya harus diidentifikasi oleh URI. Dan PUT secara logis dilakukan untuk URI yang sama dan muatannya akan terlihat persis seperti apa yang Anda inginkan GET berikutnya.

Anda dapat menggunakan POST untuk URI yang berbeda, tetapi itu hanya akan kurang masuk akal karena tidak perlu asimetris dengan GET. POST ke URI umum hanya masuk akal untuk menciptakan sumber daya baru ( POST /users/new, payload:, {name: "Adrian"}respon {id: 345, name: "Adrian"}), tetapi itu tidak idempoten dan karena itu harus dihindari jika Anda berjuang untuk REST¹. Alih-alih, Anda harus memesan ID dengan satu panggilan dan kemudian menggunakan PUT untuk mengatur ID baru; itu toleran terhadap kesalahan, karena jika permintaan pertama gagal, reservasi ID akhirnya bisa habis dan PUTidempoten. Atau gunakan UUID yang dihasilkan klien.


¹ Definisi REST tidak mengatakan apa-apa tentang idempoten, jadi saya tidak bisa benar-benar mengklaim itu bukan REST jika Anda memiliki operasi non-idempoten. Itu tidak mengubah fakta bahwa berpegang pada permintaan idempoten membuat hal-hal lebih dapat diandalkan tanpa menyulitkan mereka dan karenanya direkomendasikan.

Jan Hudec
sumber
3
Sejauh yang saya tahu permintaan POST tidak harus idempoten. Jadi saya tidak melihat masalah dengan memposting /users(tidak perlu menambahkan 'baru').
lex82
terima kasih untuk balasan Anda. Saya melihat bahwa ini adalah fitur yang bagus untuk memiliki idempotensi untuk semua permintaan tetapi siapa bilang ini diperlukan untuk REST API? Tentu saja banyak API yang menyebut dirinya RESTful memungkinkan permintaan POST non-idempoten (terutama ketika server menghasilkan id untuk sumber daya baru). Tetapi bahkan jika Anda menerapkan definisi REST yang sangat ketat, saya tidak melihat kendala arsitektur mana yang dilanggar dengan POST non idempoten seperti contoh di atas.
lex82
Saya pasti bisa membayangkan permintaan POST yang melanggar batasan. Saya hanya tidak melihat mengapa memposting sumber daya ke dalam koleksi dan membiarkan server memutuskan idnya merupakan pelanggaran batasan REST.
lex82
3
Seluruh gagasan POST bukan untuk menjadi idempoten ....
EralpB
2

Memikirkan hal ini lagi, kami menggabungkan sumber daya ke URI.

Jika URI tidak memiliki ID, payload perlu diubah:

PUT / no / id / di sini Payload: {name: "Adrian"} <Pengguna apa ???

Apakah ada alasan untuk tidak melakukannya?

Jawaban untuk pertanyaan ini tergantung pada apakah Anda ingin mengizinkan klien untuk mengubah ID?

Jika klien dapat mengubah ID, melalui PUT, maka URI untuk sumber daya akan berubah, dan Anda harus memberikan 301 Pindah Secara Permanen kapan saja sumber daya mengakses URI yang lama.

Jadi misalnya Anda mulai dengan sumber daya di

/users/123

dan klien PUT berikut ini ke sumber daya

{id: 222, name: "Adrian"}

sumber daya telah diperbarui dan URI-nya sekarang

/users/222

The Locationlapangan di respon PUT harus berisi URI baru, dan jika Anda pergi ke /users/123Anda harus mendapatkan 301respon dengan Lokasi lapangan menunjuk ke baru /users/222sumber daya.

Dalam kebanyakan kasus, Anda sebenarnya tidak ingin klien dapat mengubah ID, karena ini bisa menjadi sangat berantakan dengan cepat. Dalam hal ini ID adalah sesuatu yang hanya dapat diubah oleh server, dan Anda harus meninggalkannya dari tubuh PUT, karena klien tidak dapat memperbarui keadaan ini.

Jika Anda PUT suatu kebutuhan untuk URI berbeda pada sumber daya yang sama, katakanlah

/users/adian_lync

maka jika sumber daya itu tidak ada server harus membuat dan membuat dan ID ketika sedang melakukannya

Cormac Mulhall
sumber
1
Alasan kami mempertanyakan penempatan ID dalam payload adalah karena Backbone.js meneruskan ID dalam permintaan PUT secara default. Kita dapat menghentikannya, tetapi sekarang saya ingin tahu mengapa itu adalah perilaku default.
Adrian Lynch
1
Takut saya tidak terbiasa dengan Backbone.js. Tampaknya tidak perlu jika ID juga dimasukkan dalam URL. Mungkin kekhilafan dari para devs
Cormac Mulhall