Titik akhir REST untuk menampilkan pratinjau sebelum POSTing

17

Saya merancang aplikasi web baru yang didukung oleh backend REST dan HTML + JS frontend.

Ada satu metode POST untuk mengubah satu entitas (sebut Config), yang memiliki beberapa efek samping dalam banyak elemen aplikasi. Misalkan POST dilakukan dengan cara ini:

POST /api/config BODY {config: ....}

Karena itu, saya ingin menampilkan pratinjau sebelum perubahan tersebut dibuat, agar pengguna akhir dapat melihat apa yang akan berubah.

Hal pertama yang saya pikirkan adalah membuat titik akhir GET untuk pratinjau, mengirimkan badan status baru entitas. Cara ini:

GET /api/preview/items BODY {config: ....}

Dapat menunjukkan status baru untuk item dengan konfigurasi baru.

GET /api/preview/sales BODY {config: ....}

Mungkin menunjukkan keadaan baru untuk penjualan dengan konfigurasi baru.

Tampaknya ide yang baik untuk menggunakan kata kerja GET karena saya tidak mengubah keadaan aplikasi. Namun, penggunaan badan permintaan dengan permintaan GET tampaknya tidak dianjurkan .

Apakah ada praktik yang baik tentang ini? Pilihan lain mungkin untuk menyimpan konfigurasi sebagai konsep dengan satu metode dan menampilkan hasilnya dengan yang lain, tetapi itu akan memerlukan langkah tambahan dan harus mengelola konsep di server:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1
Xtreme Biker mengembalikan Monica
sumber
Apa sebenarnya konfigurasi ini dan bagaimana pengaruhnya terhadap itemsatau sales? Apakah itu memengaruhi representasi entitas yang dikembalikan?
Andy
Misalkan barang dan penjualan keduanya terpengaruh oleh perubahan yang Anda buat di konfigurasi.
Xtreme Biker mengembalikan Monica
Tapi apa artinya perubahan itu? Apakah itu mengubah set entitas yang dikembalikan? Apakah itu mengubah struktur yang dikembalikan?
Andy
Sebenarnya itu mengubah nilai untuk itemsdan sales(bukan struktur), tergantung pada konfigurasi POST Anda.
Xtreme Biker mengembalikan Monica
Dan seberapa besar konfigurasi sebenarnya? Bisakah tumbuh hingga beberapa ratus kilobyte atau bahkan lebih?
Andy

Jawaban:

27

Ini terlalu spesifik domain untuk memiliki dukungan asli dalam HTTP.

Sebagai gantinya, Anda dapat melakukan salah satu dari yang berikut:

  1. Punya a POST /api/config/preview. Di sisi server, aplikasi akan tahu bahwa itu tidak boleh mengubah konfigurasi yang sebenarnya, tetapi menggabungkan yang sebenarnya dengan yang Anda posting, dan mengembalikan hasil yang menunjukkan apa yang diubah.

    Nantinya, jika pengguna puas dengan hasilnya, ia akan melakukan yang POST /api/configmemuat muatan yang sama seperti pada permintaan sebelumnya. Ini secara efektif akan menimpa konfigurasi.

    Manfaat dari pendekatan ini adalah Anda tidak melakukan perubahan apa pun pada API saat ini. Klien yang tidak membutuhkan fitur pratinjau masih akan dapat memperbarui entri seperti sebelumnya.

    Kekurangannya adalah ketika bodinya besar, itu berarti akan diperlukan untuk mengirimnya dua kali ke server. Jika ini kasus Anda, Anda dapat menggunakan pendekatan berikutnya.

  2. Memiliki POST /api/config/prepareyang mengingat apa yang dikirim dalam catatan sementara dan mengembalikan dua hal: ID dari catatan sementara (misalnya 12345) dan pratinjau perubahan.

    Jika pengguna puas dengan hasilnya, ia akan melakukan POST /api/config/commit/12345untuk menyimpan perubahan secara definitif. Jika tidak, catatan sementara dapat disimpan untuk beberapa waktu, dan kemudian dibuang oleh pekerjaan cron.

    Keuntungannya adalah, di sini lagi, Anda dapat mempertahankan yang asli asli POST /api/config, dan klien yang tidak memerlukan pratinjau tidak akan rusak.

    Kekurangannya adalah bahwa (1) menangani penghapusan catatan sementara bisa rumit (apa yang membuat Anda berpikir bahwa satu jam sudah cukup? Bagaimana jika sepuluh menit kemudian, Anda kehabisan memori? Bagaimana klien menangani HTTP 404 saat melakukan komit catatan yang kedaluwarsa?) dan bahwa (2) penyerahan catatan dua langkah mungkin lebih rumit dari yang seharusnya.

  3. Pindahkan logika pratinjau di sisi klien.

Arseni Mourzenko
sumber
Bagaimana dengan Mengirim tajuk yang berbunyi "jangan teruskan ini, tunjukkan saja padaku bagaimana-jika"? Saya akan mengeditnya menjadi jawaban jika tidak apa-apa dengan Anda @ ArseniMourzenko
marstato
1
@marstato: secara pribadi, saya tidak terlalu menyukai header HTTP untuk penggunaan itu. Meskipun mungkin masuk akal untuk orang lain, jadi saya baik-baik saja jika Anda mengedit jawaban saya. Perhatikan bahwa Anda juga dapat memposting jawaban Anda sendiri, yang akan memungkinkan orang lain untuk meningkatkannya (dan akan memberi Anda poin reputasi).
Arseni Mourzenko
Saya kira opsi 1 lebih cocok untuk kasus saya. Jadi, Anda POST konfigurasi pratinjau dan Anda memiliki perubahan dalam hasilnya, daripada harus menetapkan titik akhir pratinjau untuk masing-masing entitas yang ditentukan. Tampaknya masuk akal. Satu-satunya hal adalah Anda menggunakan POST untuk tidak membuat perubahan di server, secara teknis. Opsi 3 tidak dapat digunakan dalam kasus saya.
Xtreme Biker mengembalikan Monica
1
@PedroWerneck Bisakah Anda mengembangkannya? Sepertinya saya bahwa opsi 2 mendefinisikan entitas lain (konsep konfigurasi) dan menyediakan cara stateless untuk berinteraksi dengan mereka.
Andrew mengatakan Reinstate Monica
1
@PedroWerneck Ini stateful dengan cara yang sama menyimpan konfigurasi di server stateful. Jadi aplikasi ini sudah stateful dari sudut pandang Anda dan begitu juga semua opsi untuk menambahkan fitur ini.
jpmc26
10

Titik menggunakan kata kerja HTTP spesifik untuk panggilan api yang berbeda di REST adalah untuk memanfaatkan mekanika dan harapan HTTP yang ada.

Menggunakan GET dalam hal ini tampaknya bertentangan dengan keduanya.

A. Klien perlu menyertakan tubuh dengan GET? tak terduga

B. Server mengembalikan respons berbeda terhadap get tergantung pada tubuh? istirahat spec dan mekanisme caching

Jika Anda kesulitan dengan pertanyaan RESTful, aturan saya adalah bertanya pada diri sendiri.

"Bagaimana ini lebih baik daripada hanya menggunakan POST untuk semuanya?"

Kecuali ada manfaat langsung dan jelas, pergi dengan strategi Just Use POST Stupid (JUPS)

Ewan
sumber
Tangkapan bagus Hahaha
Xtreme Biker mengembalikan Monica
@ Ewan ... terlepas dari apakah ini merupakan pendekatan pragmatis atau tidak ... jika Anda menggunakan POST untuk semuanya, perlu dicatat bahwa itu sebenarnya tidak tenang.
Allenph
1
baik, kecuali POST adalah pilihan yang tepat untuk semua metode Anda. Dan itu tidak seperti ada aturan objektif yang dapat Anda terapkan, kami hanya akan berdebat interpretasi subyektif kami tentang apa yang sedikit lebih dari sekedar pedoman.
Ewan
6

Anda dapat mengirim tajuk yang menunjukkan ke server "jangan bertahan, tunjukkan saja kepada saya apa hasilnya jika Anda melakukannya". Misalnya

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

Di mana server dapat merespons:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

Perhatikan bahwa, jika Anda menggunakan O / RM dan / per transaksi berdasarkan Satuan Kerja dengan DB Anda, Anda dapat dengan mudah menerapkan fungsi ini untuk semua titik akhir Anda tanpa memerlukan pekerjaan pada titik akhir tertentu: Jika ada permintaan dengan opsi itu , gulung kembali transaksi / unit kerja alih-alih melakukannya.

marstato
sumber
@PeterRader poin bagus, menghapusX-
marstato
Sama-sama. Apakah Anda mengatakan entitas yang sedang dalam simulasi harus direpresentasikan sebagai "dalam simulasi"?
Peter Rader
Tidak; Itulah titik simulasi, bukan? Nilai tajuk juga bisa nonetetapi itu akan - untuk seleraku - bertentangan terlalu banyak dengan sifat POSTmetode.
marstato
2

Saya sarankan memperlakukan ini dengan cara yang sama seperti Anda memperlakukan pencarian. Saya akan mengatur titik akhir POST di /api/config/previewmana MENCIPTAKAN pratinjau baru. Kemudian saya akan mengatur titik akhir PUT atau PATCH api/configtergantung pada apakah Anda bermaksud mengedit konfigurasi saat ini, atau hanya mengganti seluruh konfigurasi (mungkin dalam kasus sebelumnya Anda akan mengirim pratinjau yang baru saja Anda buat).

Allenph
sumber
0

Bersamaan dengan jawaban baik lainnya, opsi lain bisa memposting konfigurasi seperti yang disebutkan, dan memiliki proses rollback juga tersedia. Saya pikir, seperti metodologi Agile, lebih baik untuk tidak terlalu takut terhadap perubahan dengan memiliki prosedur yang lebih terperinci, berulang, dan teruji, dan ini akan memberi Anda cadangan ketika Anda membutuhkannya, mengurangi risiko menjadi sedikit atau tidak sama sekali, tergantung pada aplikasi .

Kemudian lagi, jika Anda mungkin memiliki kesalahan konfigurasi yang mempengaruhi keseluruhan sistem, Anda ingin menanganinya lebih aktif, dan jika itu masalahnya, mengapa tidak hanya berupaya mempratinjau perubahan pada titik itu, dari perspektif server atau klien. Meskipun, saya bisa melihat bagaimana fitur pratinjau ini bisa lebih mahal untuk dikembangkan, di kasing kasus memiliki serangkaian langkah yang berbeda untuk diikuti dan diuji.

Pisis
sumber
0

RFC6648 mencabut X-konstruksi baru jadi saya harus memilih menentang gagasan untuk mengirim bidang-header baru. REST adalah gaya arsitektur, yang kita bicarakan adalah RESTful - tetapi mari kita abaikan itu untuk saat ini.

Karena REST adalah Representative (dan simulasi tidak memiliki representasi dalam kenyataan) dan Stateful (dan simulasi bukanlah keadaan sampai komitmennya dilakukan), kita harus memiliki ruang lingkup baru, seperti ruang lingkup simulasi. Tetapi kita harus menyebutnya emulasi alih-alih simulasi karena simulasi mencakup proses simulasi tetapi stateful berarti kita memiliki status berdiri, solusi ideal simulasi: emulasi. Jadi kita perlu menyebutnya emulasi dalam URL. Ini mungkin juga solusi yang baik:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

Ada pendekatan lain .... Anda mungkin memperhatikan bahwa ada banyak permintaan dari klien HTML / JavaScript dapat menghasilkan terlalu banyak permintaan , yang mencapai batas sekitar 17 permintaan pada saat yang sama (lihat halaman ini ). Anda dapat menukar penggunaan REST dan alih-alih memberikan status objek yang lemah, Anda dapat memberikan kondisi halaman khusus pengguna yang kaya. Contoh:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

Salam

Peter Rader
sumber