Bagaimana cara mendesain API REST untuk menangani operasi non-CRUD?

11

Saya mencoba untuk mengonversi seperangkat layanan berbasis SOAP ke API yang tenang.

Saya mulai dengan mengidentifikasi sumber daya dengan menganalisis nama operasi dan saya mendapatkan sumber dayanya Subscription.

Ketika saya perlu memperbarui status langganan, saya tidak bisa begitu saja mengirim POSTpermintaan ke server, karena saya tidak memiliki akses langsung ke sumber daya, tetapi saya perlu menelepon beberapa operasi bergaya RPC untuk memperbarui propertinya. Selain itu, hanya dan hanya jika saya mengubah status langganan menjadi "aktif", diperlukan panggilan tambahan ke layanan eksternal.

Dalam kasus ini, apa praktik terbaik untuk menangani operasi yang mendasarinya?

Solusi yang saya buat adalah dengan menggunakan parameter kueri, sehingga jika saya perlu memanggil layanan aktivasi, saya dapat menggunakan sesuatu seperti:

POST /subscriptions/{subscriptionid}/?activate=true

Mengingat saya tidak dapat secara langsung memperbarui bidang objek Langganan saya, apakah ada praktik terbaik untuk menangani konversi semacam ini?

Pembaruan 1:

Saya dapat memasukkan beberapa nilai permintaan POST saya, misalnya "status": "aktif"

dan periksa di dalam layanan saya operasi yang tepat untuk dipicu.

Vektor88
sumber
Pemetaan perintah REST ke kata kerja HTTP gagal dengan operasi yang kompleks. Anda lebih baik hanya melakukan panggilan gaya RPC POST activSubscription / {id} tidak ada yang akan bingung dengan hal itu
Ewan
@ Ewan Saya tidak yakin ini sesuai dengan model RESTful, tapi saya datang dengan solusi lain: dalam kode saya, saya dapat memanggil operasi gaya RPC yang tepat sesuai dengan muatan input (saya dapat melewati status = aktif di tubuh permintaan posting saya, kode akan memanggil kode aktivasi)
Vektor88
1
Pembaruan untuk sumber daya yang ada seperti ini harus menjadi PATCH, dan badan permintaan kemudian merupakan model parsial dari apa yang Anda ubah. POST seharusnya merupakan permintaan yang menciptakan sumber daya. Perbedaan ini, selain lebih jelas bagi pengguna, akan memudahkan kode Anda untuk mengetahui kapan operasi ini terjadi daripada posting sumber daya.
Mr Cochese
1
@ Vektor88 Biasanya, tetapi itu adalah operasi idempoten di mana Anda harus melewati seluruh representasi status sumber daya. Kasus penggunaan ini tampaknya jauh lebih mirip pembaruan parsial, yang sangat cocok dengan PATCH.
Mr Cochese
1
@MrCochese POST bukan idempoten.
JimmyJames

Jawaban:

8

Anda perlu menonton ceramah ini oleh Jim Webber.

Ketika saya perlu memperbarui status berlangganan, saya tidak bisa begitu saja mengirim permintaan POST ke server, karena saya tidak memiliki akses langsung ke sumber daya, tetapi saya perlu memanggil beberapa operasi bergaya RPC untuk memperbarui propertinya. Selain itu, hanya dan hanya jika saya mengubah status langganan menjadi "aktif", diperlukan panggilan tambahan ke layanan eksternal.

Pikirkan "perpesanan"; mengirim pesan ke domain Anda, menjelaskan apa yang Anda inginkan terjadi. Efek samping dari pesan adalah bahwa model domain Anda benar-benar mengubah kondisinya. "Sumber daya" adalah antrian pesan.

POST /subscriptions/{subscriptionid}/?activate=true

Ejaan nama sumber tidak penting bagi mesin; tetapi orang-orang cenderung rewel ketika pengidentifikasi yang Anda gunakan berhenti dari konvensi bahwa sumber daya adalah "kata benda".

Juga, kita berbicara tentang sumber daya yang berada di bawahnya /subscriptions/{subscriptionid}, jadi konvensi (lihat RFC 3986 ) menyerukan untuk mengekspresikan hubungan itu dengan segmen jalur, daripada menggunakan bagian permintaan.

Jadi ejaan ini mungkin masuk akal

POST /subscriptions/{subscriptionid}/messages
POST /subscriptions/{subscriptionid}/activations
VoiceOfUnreason
sumber
1
Pembicaraan Jim Webber tersedia di youtube.com/watch?v=aQVSzMV8DWc
user674669
0

Jika ini adalah boolean flag untuk mengaktifkan / menonaktifkan hal-hal, saya akan mengatakan defaultnya adalah menggunakan JSON:

POST /subscriptions/{subscriptionid}/
{
    format: 0,
    subscription: 
    {
        active: false
    }
}

Ini mudah diperpanjang jika Anda ingin mendukung lebih banyak properti. Pendekatan lain adalah memberikan titik akhir sendiri:

POST /subscriptions/{subscriptionid}/active/
DELETE /subscriptions/{subscriptionid}/active/

Secara pribadi, saya hanya akan menggunakan ini jika activekeadaan acara ini membutuhkan / memiliki properti yang kemudian dapat Anda lewati / dapatkan di JSON, seperti ID pengguna atau pengaturan.

Jika ini bukan nilai boolean tetapi hanya tindakan yang Anda perlu memicu tetapi tidak perlu / memiliki umpan balik status untuk (kecuali 200 OK segera), saya akan menggunakan titik akhir seperti ini untuk memicu seperti RPC:

POST /subscriptions/{subscriptionid}/activate/

Jika ragu, baca ini: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful (lihat "Bagaimana dengan tindakan yang tidak sesuai dengan dunia operasi CRUD? ")

Barry Staes
sumber
0

REST tidak berfungsi. Activateadalah kata kerja dan tidak bisa menjadi negara, Activeadalah negara.

Karena RESTful tidak berfungsi, Anda tidak dapat memberi tahu layanan RESTful apa yang harus dilakukan, tetapi Anda dapat menambahkan pekerjaan untuk antrian layanan.

Lihat ini:

PUT /subscriptionQueue
subscriptionId={subscriptionId}
active=true

Permintaan ini tenang dan mendukung semua manfaat tenang (seperti kinerja, asam ...)

Peter Rader
sumber