Saya menulis layanan tenang untuk sistem manajemen pelanggan dan saya mencoba untuk menemukan praktik terbaik untuk memperbarui catatan secara parsial. Misalnya, saya ingin penelepon dapat membaca catatan lengkap dengan permintaan GET. Tetapi untuk memperbaruinya hanya operasi tertentu pada catatan yang diizinkan, seperti mengubah status dari ENABLED ke DISABLED. (Saya punya skenario yang lebih kompleks dari ini)
Saya tidak ingin penelepon menyerahkan seluruh catatan hanya dengan bidang yang diperbarui untuk alasan keamanan (rasanya juga berlebihan).
Apakah ada cara yang disarankan untuk membangun URI? Saat membaca buku REST, panggilan gaya RPC tampaknya disukai.
Jika panggilan berikut mengembalikan catatan pelanggan lengkap untuk pelanggan dengan id 123
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
bagaimana saya harus memperbarui status?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
Pembaruan : Untuk menambah pertanyaan. Bagaimana cara memasukkan 'panggilan logika bisnis' ke api REST? Apakah ada cara yang disepakati untuk melakukan ini? Tidak semua metode CRUD secara alami. Beberapa lebih kompleks, seperti ' sendEmailToCustomer (123) ', ' mergeCustomers (123, 456) ', ' countCustomers () '
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
POST
dari Roy Fielding sendiri: roy.gbiv.com/untangled/2009/it-is-okay-to-use-post di mana ide dasarnya adalah: jika tidak ada metode (sepertiGET
atauPUT
) cocok untuk penggunaan operasi AndaPOST
.Jawaban:
Anda pada dasarnya memiliki dua opsi:
Gunakan
PATCH
(tetapi perhatikan bahwa Anda harus menentukan jenis media Anda sendiri yang menentukan apa yang akan terjadi dengan tepat)Gunakan
POST
untuk sub sumber daya dan kembalikan 303 Lihat Lainnya dengan tajuk Lokasi yang menunjuk ke sumber daya utama. Maksud dari 303 adalah untuk memberi tahu klien: "Saya telah melakukan POST Anda dan efeknya adalah bahwa beberapa sumber daya lain telah diperbarui. Lihat header Lokasi untuk sumber daya yang mana." POST / 303 dimaksudkan untuk penambahan berulang ke sumber daya untuk membangun keadaan beberapa sumber daya utama dan itu sangat cocok untuk pembaruan parsial.sumber
Anda harus menggunakan POST untuk pembaruan sebagian.
Untuk memperbarui bidang untuk pelanggan 123, buat POST ke / pelanggan / 123.
Jika Anda ingin memperbarui hanya statusnya, Anda juga dapat PUT ke / pelanggan / 123 / status.
Umumnya, permintaan GET tidak boleh memiliki efek samping, dan PUT adalah untuk menulis / mengganti seluruh sumber daya.
Ini mengikuti langsung dari HTTP, seperti yang terlihat di sini: http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods
sumber
/customer/123
harus membuat hal yang jelas yang secara logis di bawah pelanggan 123. Mungkin pesanan? TETAPI/customer/123/status
tampaknya lebih masuk akal, dengan asumsi POST/customers
secara implisit menciptakanstatus
(dan menganggap itu sah REST).POST
-pertanyaan tidak perlu non-idempoten. Dan seperti yang disebutkan,PUT
harus mengganti seluruh sumber daya.Anda harus menggunakan PATCH untuk pembaruan sebagian - baik menggunakan dokumen json-patch (lihat http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-08 atau http://www.mnot.net/ blog / 2012/09/05 / patch ) atau framework patch XML (lihat http://tools.ietf.org/html/rfc5261 ). Namun menurut saya, json-patch adalah yang paling cocok untuk jenis data bisnis Anda.
PATCH dengan dokumen patch JSON / XML memiliki semantik maju sangat selat untuk pembaruan parsial. Jika Anda mulai menggunakan POST, dengan salinan yang diubah dari dokumen asli, untuk pembaruan parsial Anda segera mengalami masalah di mana Anda ingin nilai yang hilang (atau, lebih tepatnya, nilai nol) untuk mewakili "abaikan properti ini" atau "setel properti ini ke nilai kosong "- dan itu mengarah ke lubang kelinci dari solusi yang diretas yang pada akhirnya akan menghasilkan jenis format tambalan Anda sendiri.
Anda dapat menemukan jawaban yang lebih mendalam di sini: http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html .
sumber
Saya mengalami masalah yang sama. PUT pada sub-sumber daya tampaknya berfungsi ketika Anda hanya ingin memperbarui satu bidang. Namun, kadang-kadang Anda ingin memperbarui banyak hal: Pikirkan formulir web yang mewakili sumber daya dengan opsi untuk mengubah beberapa entri. Pengiriman formulir oleh pengguna tidak boleh menghasilkan beberapa PUT.
Berikut adalah dua solusi yang dapat saya pikirkan:
lakukan PUT dengan seluruh sumber daya. Di sisi server, tentukan semantik bahwa PUT dengan seluruh sumber daya mengabaikan semua nilai yang belum berubah.
lakukan PUT dengan sumber daya parsial. Di sisi server, tentukan semantik ini menjadi gabungan.
2 hanyalah optimasi bandwidth 1. Kadang-kadang 1 adalah satu-satunya pilihan jika sumber daya mendefinisikan beberapa bidang isian wajib (pikirkan buffer proto).
Masalah dengan kedua pendekatan ini adalah cara membersihkan bidang. Anda harus menetapkan nilai null khusus (terutama untuk buffer proto karena nilai null tidak didefinisikan untuk buffer proto) yang akan menyebabkan pembersihan bidang.
Komentar?
sumber
Untuk memodifikasi status, saya pikir pendekatan RESTful adalah dengan menggunakan sub-sumber daya logis yang menggambarkan status sumber daya. IMO ini sangat berguna dan bersih ketika Anda memiliki set status yang berkurang. Itu membuat API Anda lebih ekspresif tanpa memaksakan operasi yang ada untuk sumber daya pelanggan Anda.
Contoh:
Layanan POST harus mengembalikan pelanggan yang baru dibuat dengan id:
GET untuk sumber daya yang dibuat akan menggunakan lokasi sumber daya:
GET / pelanggan / 123 / tidak aktif harus mengembalikan 404
Untuk operasi PUT, tanpa menyediakan entitas Json, ia hanya akan memperbarui status
Memberikan entitas akan memungkinkan Anda untuk memperbarui konten pelanggan dan memperbarui status pada saat bersamaan.
Anda membuat sub-sumber daya konseptual untuk sumber daya pelanggan Anda. Ini juga konsisten dengan definisi Roy Fielding tentang sumber daya: "... Sumber daya adalah pemetaan konseptual untuk satu set entitas, bukan entitas yang sesuai dengan pemetaan pada titik waktu tertentu ..." Dalam hal ini pemetaan konseptual adalah pelanggan aktif ke pelanggan dengan status = AKTIF.
Baca operasi:
Jika Anda melakukan panggilan-panggilan itu satu per satu setelah yang lainnya harus mengembalikan status 404, output yang berhasil mungkin tidak termasuk status karena itu implisit. Tentu saja Anda masih dapat menggunakan GET / pelanggan / 123? Status = ACTIVE | INACTIVE untuk meminta sumber daya pelanggan secara langsung.
Operasi DELETE menarik karena semantiknya dapat membingungkan. Tetapi Anda memiliki pilihan untuk tidak menerbitkan operasi itu untuk sumber daya konseptual ini, atau menggunakannya sesuai dengan logika bisnis Anda.
Yang satu dapat membawa pelanggan Anda ke status DELETED / DISABLED atau ke status yang berlawanan (AKTIF / TIDAK AKTIF).
sumber
Hal-hal untuk ditambahkan ke pertanyaan Anda yang ditambah. Saya pikir Anda sering dapat merancang aksi bisnis yang lebih rumit dengan sempurna Tetapi Anda harus memberikan metode / prosedur gaya berpikir dan berpikir lebih dalam sumber daya dan kata kerja.
pengiriman surat
Implementasi sumber daya ini + POST kemudian akan mengirimkan surat. jika perlu Anda bisa menawarkan sesuatu seperti / pelanggan / 123 / kotak keluar dan kemudian menawarkan tautan sumber daya ke / pelanggan / mails / {mailId}.
jumlah pelanggan
Anda bisa menanganinya seperti sumber pencarian (termasuk metadata pencarian dengan informasi paging dan num-found, yang memberi Anda jumlah pelanggan).
sumber
Gunakan PUT untuk memperbarui sumber daya tidak lengkap / parsial.
Anda dapat menerima jObject sebagai parameter dan menguraikan nilainya untuk memperbarui sumber daya.
Di bawah ini adalah fungsi yang dapat Anda gunakan sebagai referensi:
sumber
Mengenai Pembaruan Anda.
Konsep CRUD saya percaya telah menyebabkan beberapa kebingungan mengenai desain API. CRUD adalah konsep umum tingkat rendah untuk operasi dasar untuk dilakukan pada data, dan kata kerja HTTP hanyalah metode permintaan ( dibuat 21 tahun yang lalu ) yang mungkin atau mungkin tidak memetakan ke operasi CRUD. Bahkan, coba cari keberadaan akronim CRUD dalam spesifikasi HTTP 1.0 / 1.1.
Panduan yang dijelaskan dengan sangat baik yang menerapkan konvensi pragmatis dapat ditemukan dalam dokumentasi API platform Google cloud . Ini menjelaskan konsep di balik pembuatan API berbasis sumber daya, yang menekankan sejumlah besar sumber daya dibandingkan operasi, dan termasuk kasus penggunaan yang Anda gambarkan. Meskipun hanya desain konvensi untuk produk mereka, saya pikir itu masuk akal.
Konsep dasar di sini (dan yang menghasilkan banyak kebingungan) adalah pemetaan antara "metode" dan kata kerja HTTP. Satu hal adalah menentukan "operasi" (metode) apa yang akan dilakukan API Anda atas jenis sumber daya apa (misalnya, mendapatkan daftar pelanggan, atau mengirim email), dan yang lainnya adalah kata kerja HTTP. Harus ada definisi dari keduanya, metode dan kata kerja yang Anda rencanakan untuk digunakan dan pemetaan di antara keduanya .
Hal ini juga mengatakan bahwa, ketika operasi tidak peta persis dengan metode standar (
List
,Get
,Create
,Update
,Delete
dalam hal ini), kita bisa menggunakan "metode Custom", sepertiBatchGet
, yang mengambil beberapa objek berdasarkan beberapa masukan objek id, atauSendEmail
.sumber
RFC 7396 : JSON Merge Patch (diterbitkan empat tahun setelah pertanyaan diposting) menjelaskan praktik terbaik untuk PATCH dalam hal format dan aturan pemrosesan.
Singkatnya, Anda mengirimkan HTTP PATCH ke sumber daya target dengan jenis media aplikasi / merge-patch + json MIME dan sebuah badan yang hanya mewakili bagian-bagian yang ingin Anda ubah / tambahkan / hapus lalu ikuti aturan pemrosesan di bawah ini.
Aturan :
Contoh kasus uji yang menggambarkan aturan di atas (seperti yang terlihat dalam lampiran RFC itu):
sumber
Lihat http://www.odata.org/
Itu mendefinisikan metode MERGE, jadi dalam kasus Anda itu akan menjadi seperti ini:
Hanya
status
properti yang diperbarui dan nilai-nilai lainnya dipertahankan.sumber
MERGE
kata kerja HTTP yang valid?MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE.
Lihat docs.oasis-open.org/odata/new-in-odata/v4.0/cn01/…Itu tidak masalah. Dalam hal REST, Anda tidak dapat melakukan GET, karena itu tidak dapat di-cache, tetapi tidak masalah jika Anda menggunakan POST atau PATCH atau PUT atau apa pun, dan tidak masalah seperti apa bentuk URL itu. Jika Anda melakukan REST, yang penting adalah ketika Anda mendapatkan representasi sumber daya Anda dari server, representasi itu dapat memberikan opsi transisi keadaan klien.
Jika respons GET Anda memiliki transisi status, klien hanya perlu tahu cara membacanya, dan server dapat mengubahnya jika perlu. Di sini pembaruan dilakukan menggunakan POST, tetapi jika itu diubah menjadi PATCH, atau jika URL berubah, klien masih tahu cara membuat pembaruan:
Anda dapat memberikan daftar parameter yang diperlukan / opsional untuk diberikan klien kepada Anda. Tergantung aplikasinya.
Sejauh operasi bisnis, itu mungkin sumber daya yang berbeda terkait dengan sumber daya pelanggan. Jika Anda ingin mengirim email ke pelanggan, mungkin layanan itu adalah sumber dayanya sendiri yang dapat Anda POST, sehingga Anda dapat menyertakan operasi berikut dalam sumber daya pelanggan:
Beberapa video bagus, dan contoh arsitektur REST presenter adalah ini. Stormpath hanya menggunakan GET / POST / DELETE, yang baik-baik saja karena REST tidak ada hubungannya dengan operasi apa yang Anda gunakan atau bagaimana tampilan URL (kecuali GET harus dapat di-cache):
https://www.youtube.com/watch?v=pspy1H6A3FM ,
https://www.youtube.com/watch?v=5WXYw4J4QOU ,
http://docs.stormpath.com/rest/quickstart/
sumber