Apa pola terbaik untuk menambahkan item yang ada ke koleksi di REST API?

23

Saya merancang REST API pragmatis dan saya sedikit bingung tentang cara terbaik untuk menambahkan entitas yang ada ke koleksi. Model domain saya mencakup Proyek yang memiliki koleksi Situs. Ini adalah hubungan banyak-ke-banyak yang ketat dan saya tidak perlu membuat entitas yang secara eksplisit memodelkan hubungan (yaitu ProjectSite).

API saya akan memungkinkan konsumen untuk menambahkan Situs yang ada ke Proyek. Di mana saya menutup telepon adalah bahwa satu-satunya data yang saya butuhkan adalah ProjectId dan SiteId. Ide awal saya adalah:

1. POST myapi/projects/{projectId}/sites/{siteId}

Tapi saya juga memikirkannya

2. POST myapi/projects/{projectId}/sites

dengan entitas Situs yang dikirim sebagai konten JSON.

Opsi 1 sederhana dan berfungsi tetapi tidak terasa benar, dan saya memiliki hubungan lain yang tidak dapat mengikuti pola ini sehingga menambah ketidakkonsistenan pada API saya.

Opsi 2 terasa lebih baik tetapi mengarah ke dua masalah:

  • Haruskah saya membuat Situs atau melemparkan pengecualian jika Situs baru diposting (SiteId = 0)?
  • Karena saya hanya perlu ProjectId dan SiteId untuk membuat hubungan, situs dapat diposting dengan data yang salah atau hilang untuk properti lainnya.

Opsi ketiga adalah memberikan titik akhir sederhana hanya untuk membuat dan menghapus hubungan. Titik akhir ini akan mengharapkan muatan JSON yang hanya berisi ProjectId dan SiteId.

Apa yang kamu pikirkan?

Ide Jamie
sumber
2
Lihat juga: stackoverflow.com/questions/2001773/…
Rory Hunter
@RoryHunter Ada beberapa diskusi menarik di tautan itu tetapi tidak ada yang menghilangkan ketidakpastian saya. Saya terutama suka bahwa jawaban yang diterima menyatakan "Anda mengerti benar." dan tempat ke-2 (walaupun dengan margin besar) menjawab "Sederhananya, Anda melakukan ini sepenuhnya mundur."
Jamie Ide
Pilihan pertama Anda baik-baik saja meskipun saya akan menggunakan PUT daripada POST karena klien mengendalikan identitas yang ditambahkan ke koleksi. Kekhawatiran pertama Anda dengan opsi 2 sepenuhnya terserah Anda, jika Anda tidak ingin situs baru, jangan melemparkan pengecualian tetapi kembalikan salah satu kode 4xx. Kekhawatiran kedua Anda tidak di sini atau di sana. Anda seharusnya tidak memposting seluruh Situs kecuali Anda mengizinkan penambahan. Menambahkan situs yang sudah ada harus memiliki id hanya saat Anda memodifikasi situs tetapi hanya koleksi "ProjectSite" (bahkan jika Anda tidak membuat sumber daya terpisah untuk itu).
Marjan Venema

Jawaban:

14

POST adalah kata kerja "append", dan juga kata kerja "processing". PUT adalah kata kerja "buat / perbarui" (untuk pengidentifikasi yang dikenal), dan hampir terlihat seperti pilihan yang tepat di sini, karena target penuh URI diketahui. projectIddan siteIdsudah ada, jadi Anda tidak perlu "POST ke koleksi" untuk menghasilkan ID baru.

Masalah dengan PUT adalah bahwa itu membutuhkan tubuh menjadi representasi dari sumber daya yang Anda PUTting. Tetapi maksudnya di sini adalah untuk menambah sumber daya koleksi "proyek / situs", daripada memperbarui sumber daya Situs.

Bagaimana jika seseorang PUT representasi JSON lengkap dari Situs yang ada? Haruskah Anda memperbarui koleksi dan memperbarui objek? Anda bisa mendukungnya, tapi sepertinya itu bukan maksudnya. Seperti yang Anda katakan,

satu-satunya data yang benar-benar saya butuhkan adalah ProjectId dan SiteId

Sebaliknya, saya akan mencoba POSTing siteIdke koleksi, dan mengandalkan sifat "append" dan "proses" POST:

POST myapi / proyek / {projectId} / situs

{'id': '...'}

Karena Anda memodifikasi sumber daya kumpulan situs dan bukan sumber daya situs , itulah URI yang Anda inginkan. POST bisa tahu untuk "menambahkan / memproses" dan menambahkan elemen dengan id itu ke kumpulan situs proyek.

Itu masih meninggalkan pintu terbuka untuk membuat situs baru untuk proyek dengan menyempurnakan JSON dan menghilangkan id. "Tidak ada id" == "buat dari awal". Tetapi jika koleksi URI mendapatkan id dan tidak ada yang lain, cukup jelas apa yang perlu terjadi.

Pertanyaan menarik. :)

rampok
sumber
Saya dari keyakinan yang percaya POST adalah untuk membuat dan PUT adalah untuk pembaruan tetapi kesimpulan Anda adalah di mana saya berakhir kemarin. Yang menyenangkan adalah bahwa berkat atribut routing di Web API, saya memiliki kode di pengontrol ProjectSites sehingga kodenya terorganisasi dengan baik.
Jamie Ide
Saya pikir alasan utama yang perlu Anda gunakan POSTdaripada PUTatau di PATCHsini adalah bahwa Anda tidak memiliki seluruh Siteentitas untuk dimasukkan ke sitessumber daya. Anda hanya memiliki id, yang membutuhkan pemrosesan agar dapat menambahkannya ke koleksi.
naksir
4

Kami menggunakan Patchmetode untuk hal-hal seperti ini. Yang ingin Anda lakukan adalah memodifikasi Proyek yang ada untuk menambahkan Situs ke dalamnya.

Jadi sesuatu seperti ini akan berhasil

PATCH myapi/projects/{id} 

dengan entitas Situs sebagai JSON / JSONArray di badan permintaan.

Dengan cara itu Anda dapat menggunakan URL yang sama untuk memodifikasi bagian-bagian berbeda dari Proyek jika Anda perlu - kode Anda dalam implementasi harus cukup cerdas untuk menangani modifikasi parsial sumber daya ini.

juan
sumber
Pendekatan yang menarik. Saya memiliki model domain "kaya" (yaitu sangat tergantung) yang lebih lama dan Project terutama memiliki banyak koleksi yang menggantungnya. Mendeteksi tipe entitas yang ada dalam permintaan akan menjadi tantangan dan tidak sesuai dengan tujuan pragmatis saya.
Jamie Ide
Mengapa ada tantangan? Jika Anda memiliki batasan-batasan itu, Anda selalu dapat menggunakan JSON yang membuat eksplisit seperti apa yang dikirim ... seperti {"sites": [], "other-stuff": {}}, Anda kemudian dapat melakukan percabangan kode Anda untuk menangani semua "orang" dengan sangat mudah. Ini benar-benar tergantung pada masalah spesifik Anda, tetapi saya masih akan merekomendasikan menggunakan PATCH karena dirancang khusus untuk hal-hal semacam ini.
juan
Kelemahan yang saya lihat adalah 1) API tidak secara eksplisit berkomunikasi dengan koleksi mana yang memungkinkan perubahan; 2) tidak dapat memanfaatkan pengikatan parameter API Web; 3) beralih besar atau jika pernyataan.
Jamie Ide
Saya belum pernah melihat metode tambalan yang digunakan di tempat lain
NimChimpsky
Bukankah PATCHjuga mengharapkan entitas penuh untuk diteruskan sebagai nilainya di sini, alih-alih id yang menunjuk ke beberapa entitas?
naksir