Saat mendesain antarmuka RESTful, semantik dari tipe permintaan dianggap penting untuk desain.
- DAPATKAN - Daftar koleksi atau ambil elemen
- PUT - Ganti koleksi atau elemen
- POST - Buat koleksi atau elemen
- HAPUS - Ya, erm, hapus koleksi atau elemen
Namun, ini sepertinya tidak mencakup konsep "pencarian".
Misalnya dalam mendesain rangkaian layanan web yang mendukung situs Pencarian Kerja, Anda mungkin memiliki persyaratan berikut:
- Dapatkan Iklan Pekerjaan individual
- GET ke
domain/Job/{id}/
- GET ke
- Buat Iklan Pekerjaan
- POST ke
domain/Job/
- POST ke
- Perbarui Iklan Pekerjaan
- PUT ke
domain/Job/
- PUT ke
- Hapus Iklan Pekerjaan
- HAPUS ke
domain/Job/
- HAPUS ke
"Dapatkan Semua Pekerjaan" juga sederhana:
- GET ke
domain/Jobs/
Namun, bagaimana pekerjaan "pencarian" jatuh ke dalam struktur ini?
Anda dapat mengklaim itu adalah variasi "koleksi daftar" dan terapkan sebagai:
- GET ke
domain/Jobs/
Namun, pencarian bisa rumit dan sangat mungkin untuk menghasilkan pencarian yang menghasilkan string GET panjang. Artinya, merujuk pertanyaan SO di sini , ada masalah menggunakan string GET lebih lama dari sekitar 2000 karakter.
Contoh mungkin dalam pencarian faceted - melanjutkan contoh "pekerjaan".
Saya dapat mengizinkan untuk mencari di aspek - "Teknologi", "Judul Pekerjaan", "Disiplin" serta kata kunci teks bebas, usia pekerjaan, lokasi dan gaji.
Dengan antarmuka pengguna yang lancar dan sejumlah besar teknologi dan jabatan, layak dilakukan pencarian yang dapat mencakup sejumlah besar pilihan segi.
Tweak contoh ini ke CV, daripada pekerjaan, membawa lebih banyak aspek, dan Anda dapat dengan mudah membayangkan pencarian dengan seratus aspek yang dipilih, atau bahkan hanya 40 aspek yang masing-masing terdiri dari 50 karakter (misalnya Judul Pekerjaan, Nama Universitas, Nama Pemberi Kerja).
Dalam situasi itu mungkin diinginkan untuk memindahkan PUT atau POST untuk memastikan bahwa data pencarian akan dikirim dengan benar. Misalnya:
- POST ke
domain/Jobs/
Namun secara semantik itu adalah instruksi untuk membuat koleksi.
Anda juga bisa mengatakan Anda akan mengungkapkan ini sebagai kreasi pencarian:
- POST ke
domain/Jobs/Search/
atau (seperti yang disarankan oleh burninggramma di bawah)
- POST ke
domain/JobSearch/
Semantik mungkin masuk akal, tetapi Anda tidak benar-benar membuat apa-apa, Anda membuat permintaan untuk data.
Jadi, semantik GET , tetapi GET tidak dijamin untuk mendukung apa yang Anda butuhkan.
Jadi, pertanyaannya adalah - Berusaha untuk tetap setia pada desain RESTful mungkin, sambil memastikan bahwa saya tetap dalam batasan HTTP, apa desain yang paling tepat untuk pencarian?
sumber
domain/Jobs?keyword={keyword}
. Ini berfungsi dengan baik untuk saya :) Harapan saya adalah, bahwaSEARCH
kata kerja akan menjadi standar. programmers.stackexchange.com/questions/233158/…Jawaban:
Anda jangan lupa bahwa permintaan GET memiliki beberapa keunggulan unggul dibandingkan solusi lain:
1) Permintaan GET dapat disalin dari bilah URL, mereka dicerna oleh mesin pencari, mereka "ramah". Di mana "ramah" berarti bahwa biasanya permintaan GET tidak boleh mengubah apa pun di dalam aplikasi Anda (idempoten) . Ini adalah kasus standar untuk pencarian.
2) Semua konsep ini sangat penting tidak hanya dari pengguna dan mesin pencari, tetapi dari sudut pandang arsitektur, desain API .
3) Jika Anda membuat solusi dengan POST / PUT Anda akan memiliki masalah yang tidak Anda pikirkan saat ini. Misalnya dalam hal browser tombol navigasi kembali / refresh halaman / riwayat. Ini bisa dipecahkan tentu saja, tapi itu akan menjadi solusi lain, lalu yang lain dan yang lain ...
Mempertimbangkan semua ini, saran saya adalah:
a) Anda harus bisa masuk ke dalam GET Anda dengan menggunakan struktur parameter pintar . Dalam kasus ekstrim Anda bahkan dapat menggunakan taktik seperti pencarian google ini di mana saya mengatur banyak parameter masih url super pendek.
b) Buat entitas lain di aplikasi Anda seperti JobSearch . Dengan asumsi Anda punya begitu banyak pilihan, kemungkinan Anda perlu menyimpan pencarian ini juga dan mengelolanya, jadi itu hanya membersihkan aplikasi Anda. Anda dapat bekerja dengan objek JobSearch secara keseluruhan, artinya Anda dapat mengujinya / menggunakannya dengan lebih mudah .
Secara pribadi saya akan mencoba untuk bertarung dengan semua cakar saya untuk menyelesaikannya dengan a) dan ketika semua harapan hilang, saya akan merangkak kembali dengan air mata di mata saya ke opsi b) .
sumber
domain/Jobs/Search/
, mungkin dengandomain/JobsSearch/
sebaliknya, atau apakah Anda berarti sesuatu yang berbeda? Bisakah Anda mengklarifikasi?TL; DR: DAPATKAN untuk pemfilteran, POST untuk pencarian
Saya membuat perbedaan antara memfilter hasil dari daftar koleksi vs pencarian yang kompleks. Tes lakmus yang saya gunakan pada dasarnya adalah jika saya membutuhkan lebih dari penyaringan (positif, negatif, atau kisaran) Saya menganggapnya sebagai pencarian yang lebih kompleks yang membutuhkan POST.
Ini cenderung diperkuat ketika memikirkan apa yang akan dikembalikan. Saya biasanya hanya menggunakan GET jika sumber daya memiliki sebagian besar siklus hidup lengkap (PUT, DELETE, GET, collection GET) . Biasanya dalam koleksi DAPATKAN saya mengembalikan daftar URI yang merupakan sumber daya REST yang membentuk koleksi itu. Dalam kueri yang kompleks, saya mungkin menarik dari banyak sumber daya untuk membangun respons (pikirkan SQL join) jadi saya tidak akan mengirim kembali URI, tetapi data aktual. Masalahnya adalah data tidak akan diwakili dalam sumber daya, jadi saya harus selalu mengembalikan data. Bagi saya ini adalah kasus yang jelas membutuhkan POST.
-
Sudah beberapa saat dan posting asli saya agak ceroboh jadi saya pikir saya akan memperbarui.
GET adalah pilihan intuitif untuk mengembalikan sebagian besar jenis data, koleksi sumber daya REST, data terstruktur sumber daya, bahkan muatan tunggal (gambar, dokumen, dll).
POST adalah metode catchall untuk apa pun yang tampaknya tidak sesuai dengan GET, PUT, DELETE, dll.
Pada titik ini saya pikir pencarian sederhana, pemfilteran secara intuitif masuk akal melalui GET. Pencarian kompleks tergantung pada preferensi pribadi terutama jika Anda melempar fungsi agregasi, korelasi silang (bergabung), format ulang, dll. Saya berpendapat bahwa par GET tidak boleh terlalu lama, dan itu adalah permintaan yang banyak (namun sedang disusun ) sering lebih masuk akal sebagai badan permintaan POST.
Saya juga mempertimbangkan aspek pengalaman penggunaan API. Saya umumnya ingin membuat sebagian besar metode semudah digunakan dan intuitif mungkin. Saya akan mendorong panggilan yang lebih fleksibel (dan karenanya lebih kompleks) ke dalam POST dan pada URI sumber daya yang berbeda, terutama jika itu tidak konsisten dengan perilaku sumber daya REST lainnya di API yang sama.
Either way, konsistensi mungkin lebih penting daripada apakah Anda melakukan pencarian di GET atau POST.
Semoga ini membantu.
sumber
GET /class?queryParams
. Dari perspektif pengguna, "kelas" selalu merupakan hal dan Anda tidak perlu melakukan penggabungan SQL yang aneh.Dalam REST, definisi sumber daya sangat luas. Namun sebenarnya Anda ingin menggabungkan beberapa data.
Misalnya, Google URI utama menunjuk ke sumber daya koleksi "tautan ke setiap situs di Internet". Parameter kueri mempersempitnya ke situs yang ingin Anda lihat.
(URI = pengidentifikasi sumber daya universal, yang URL = pencari sumber daya universal, di mana "http: //" yang familier adalah format default untuk URI. Jadi URL adalah pelacak, tetapi di REST ada baiknya menggeneralisasikannya ke pengenal sumber daya Namun, orang-orang menggunakannya secara bergantian.)
Dan kemudian gunakan POST, yang merupakan append atau kata kerja proses untuk menambahkan item baru ke koleksi itu:
Perhatikan bahwa itu adalah struktur yang sama untuk
job
objek dalam setiap kasus. Seorang klien dapat DAPATKAN kumpulan pekerjaan, menggunakan params pertanyaan untuk mempersempit pencarian, dan kemudian menggunakan format yang sama untuk salah satu item untuk POST pekerjaan baru. Atau dapat mengambil salah satu item dan PUT ke URI untuk memperbarui yang itu.Untuk string kueri yang sangat panjang atau rumit, konvensi membuat OK untuk mengirimnya sebagai permintaan POST. Bundel parameter kueri ke atas sebagai pasangan nama / nilai, atau objek bersarang di struktur JSON atau XML dan kirim ke badan permintaan. Misalnya, jika kueri Anda memiliki data bersarang alih-alih sekelompok pasangan nama / nilai. HTTP spec untuk POST menggambarkannya sebagai append atau kata kerja proses. (Jika Anda ingin berlayar kapal perang melalui celah di REST, gunakan POST.)
Saya akan menggunakannya sebagai rencana fallback.
Apa yang Anda kehilangan ketika Anda melakukan itu adalah a) GET adalah nullipotent - artinya, tidak mengubah apa pun - POST tidak. Jadi jika panggilan gagal, middleware tidak akan secara otomatis mencoba kembali atau menyimpan hasil, dan 2) dengan parameter pencarian di tubuh, Anda tidak dapat memotong dan menempelkan URI lagi. Artinya, URI bukan pengidentifikasi khusus untuk pencarian yang Anda inginkan.
Untuk membedakan antara "buat" dari "pencarian". Ada beberapa opsi yang konsisten dengan praktik REST:
Anda bisa melakukannya di URI dengan menambahkan sesuatu ke nama koleksi, seperti mencari pekerjaan dan bukan pekerjaan. Itu hanya berarti Anda memperlakukan koleksi pencarian sebagai sumber daya yang terpisah.
Karena semantik POST sama-sama menambahkan proses ATAU, Anda dapat mengidentifikasi badan pencarian dengan muatan. Seperti {job: ...} vs. {search: ...}. Terserah logika POST untuk memposting atau memprosesnya dengan tepat.
Itu cukup banyak preferensi desain / implementasi. Saya tidak berpikir ada konvensi yang jelas.
Jadi, seperti yang sudah Anda paparkan, idenya adalah untuk menentukan sumber daya koleksi
jobs
Cari dengan GET + permintaan params untuk mempersempit pencarian. Kueri data yang panjang atau terstruktur masuk ke tubuh POST (mungkin ke koleksi pencarian terpisah). Buat dengan POST untuk menambahkan ke koleksi. Dan perbarui dengan PUT ke URI tertentu.
(FWIW konvensi gaya dengan URI adalah menggunakan semua huruf kecil dengan kata-kata yang dipisahkan oleh tanda hubung. Tapi itu tidak berarti Anda harus melakukannya dengan cara itu.)
(Juga, saya harus mengatakan itu dari pertanyaan Anda, sudah jelas bahwa Anda berada jauh di jalan ini. Saya menjabarkan hal-hal secara eksplisit hanya untuk mengatur mereka, tetapi pertanyaan Anda telah membahas sebagian besar masalah semantik dalam hal ini). jawaban. Saya hanya mengaitkannya dengan beberapa konvensi dan latihan.)
sumber
route
tidak bisa menangani pilihan pemrosesan. Saya harus melihat itu ...Saya biasanya menggunakan query OData, mereka beroperasi sebagai panggilan GET tetapi memungkinkan Anda untuk membatasi properti yang dikembalikan dan menyaringnya.
Anda menggunakan token seperti
$select=
dan$filter=
Anda akan berakhir dengan URI yang terlihat seperti ini:Anda juga dapat melakukan paging menggunakan
$skip
dan$top
dan pemesanan.Untuk informasi lebih lanjut, lihat OData.org . Anda belum menentukan bahasa yang Anda gunakan, tetapi jika itu ASP.NET, platform WebApi mendukung permintaan OData - untuk yang lain (PHP dll) mungkin ada perpustakaan yang dapat Anda gunakan untuk menerjemahkannya ke dalam kueri basis data.
sumber
JobsNearMeAddedInTheLast7Days
atau apa pun untuk merangkum permintaan yang terlalu panjang / kompleks untuk OData dan kemudian memaparkannya hanya melalui panggilan GET .Satu pendekatan untuk dipertimbangkan adalah memperlakukan set kueri yang mungkin sebagai sumber daya pengumpulan, misalnya
/jobs/filters
.POST
permintaan untuk sumber daya ini, dengan parameter permintaan dalam tubuh, baik akan menciptakan sumber daya baru atau mengidentifikasi ada setara filter dan mengembalikan URL yang berisi ID nya:/jobs/filters/12345
.Id kemudian dapat digunakan dalam permintaan GET untuk pekerjaan:
/jobs?filter=12345
.GET
Permintaan selanjutnya pada sumber daya filter akan mengembalikan definisi filter.Pendekatan ini memiliki keuntungan yang membebaskan Anda dari format parameter kueri untuk definisi filter, berpotensi memberi Anda lebih banyak kekuatan untuk mendefinisikan filter kompleks. ATAU kondisi adalah salah satu contoh yang dapat saya pikirkan yang sulit dicapai dengan string kueri.
Kelemahan dari pendekatan ini adalah Anda kehilangan keterbacaan URL (meskipun ini dapat mengurangi dengan mengambil definisi melalui
GET
permintaan untuk sumber daya filter). Untuk alasan ini, Anda mungkin juga ingin mendukung yang sama atau subset dari parameter kueri pada/jobs
sumber daya seperti yang Anda dukung untuk sumber daya filter. Ini bisa digunakan untuk kueri yang lebih pendek. Jika fitur ini disediakan, untuk mempertahankan cacheability antara dua jenis penyaringan, ketika menggunakan parameter query pada/jobs
sumber daya, pelaksanaan harus internal membuat / menggunakan kembali sumber daya filter dan mengembalikan302
atau303
status yang menunjukkan URL dalam bentuk/jobs?filter=12345
.sumber
GET /jobs/37
dan menerima hasil, kemudian seseorang menghapus sumber daya dan 2 detik kemudian permintaan yang sama mengembalikan 404. Demikian pula jika AndaPOST /searches
dan Anda diarahkan ke hasil pencarian (pencarian dibuat dan Anda menerima 201 dengan Header lokasi ke sumber daya), 2 detik kemudian hasil itu dapat dihapus dari memori dan harus dibuat ulang. Tidak perlu penyimpanan jangka panjang.Ini adalah jawaban lama tapi saya masih bisa berkontribusi sedikit untuk diskusi. Saya sering mengamati kesalahpahaman tentang REST, RESTful, dan Architecture. RESTful tidak pernah menyebutkan apapun tentang TIDAK membangun pencarian, tidak ada dalam RESTful tentang arsitektur, itu adalah seperangkat prinsip atau kriteria desain.
Untuk menggambarkan Pencarian dengan cara yang lebih baik, kita harus berbicara tentang arsitektur khususnya dan yang lebih cocok adalah Arsitektur Berorientasi Sumber Daya (ROA).
Dalam RESTful ada prinsip untuk mendesain, idempoten tidak berarti hasilnya tidak dapat berubah ketika saya membaca dalam beberapa jawaban, itu berarti hasil dari permintaan independen tidak tergantung pada berapa kali dieksekusi. Itu bisa berubah, mari kita bayangkan saya terus memperbarui basis data yang memberinya dengan beberapa data yang dilayani oleh RESTful Api, mengeksekusi GET yang sama mungkin mengubah hasilnya tetapi tidak tergantung pada berapa kali dieksekusi. Jika saya dapat membekukan dunia itu berarti tidak ada keadaan, transformasi, apa pun di dalam layanan ketika saya meminta sumber daya yang mengarah ke hasil yang berbeda.
Dalam arsitektur berorientasi sumber daya (sebut saja ROA mulai sekarang untuk singkatnya) kami fokus pada sumber daya yang bisa menjadi banyak hal:
Apa yang membuatnya unik dalam hal sumber daya adalah addresability yang berarti hanya memiliki satu URI
Dengan cara itu pencarian sangat cocok di RESTful mempertimbangkan ROA . Kami harus menggunakan GET karena saya menganggap pencarian Anda adalah pencarian normal dan tidak mengubah apa pun, jadi idempoten (bahkan jika mengembalikan hal yang berbeda tergantung pada elemen baru yang ditambahkan). Ada kebingungan di sini dengan cara itu karena saya bisa tetap pada RESTful dan tidak ke ROA, itu berarti saya bisa mengikuti pola yang menciptakan pencarian dan mengembalikan hal-hal yang berbeda dengan parameter yang sama karena saya tidak menggunakan prinsip addressability dari ROA. Bagaimana itu? Nah, jika Anda mengirim filter pencarian di badan atau header sumber daya tidak ADDRESSABLE.
Anda dapat menemukan prinsip-prinsip apa yang sebenarnya dan URI dalam dokumen asli W3:
https://www.w3.org/DesignIssues/Axioms
Setiap URL dalam arsitektur ini harus bersifat deskriptif sendiri. Ini penting jika Anda mengikuti prinsip untuk mengatasi semua yang ada di URI, itu artinya Anda dapat menggunakan / (memangkas) untuk memisahkan apa pun yang Anda butuhkan atau parameter kueri. Kita tahu ada batasan untuk itu tetapi ini adalah pola arsitekturnya.
Mengikuti pola ROA di RESTful pencarian tidak lebih dari sumber daya lainnya, satu-satunya perbedaan adalah sumber daya berasal dari perhitungan, bukan dari hubungan langsung ke objek itu sendiri. Berdasarkan prinsip saya dapat membahas dan mendapatkan layanan perhitungan aritmatika sederhana berdasarkan pola berikut:
http://myapi.com/sum/1/2
Di mana jumlah, 1 dan 2 dapat dimodifikasi tetapi hasil perhitungannya unik dan sangat menarik, setiap kali saya menelepon dengan parameter yang sama, saya mendapatkan perubahan yang sama dan tidak ada perubahan dalam layanan. Sumber / jumlah / 1/2 dan / pengurangan / 5/4 berpegang teguh pada prinsip-prinsip dengan sempurna.
sumber
GET tidak masalah, jika Anda memiliki koleksi statis yang selalu mengembalikan hasil yang sama (representasi) untuk satu URI. Itu juga menyiratkan bahwa data yang menghasilkan representasi ini tidak pernah diubah. Sumbernya adalah database hanya-baca.
Memiliki GET mengembalikan hasil yang berbeda untuk satu dan URI yang sama melanggar idempotensi / keselamatan dan prinsip CoolURI dan akibatnya tidak tenang . Dimungkinkan untuk memiliki kata kerja idempoten menulis ke database, tetapi mereka tidak boleh mempengaruhi representasi.
Pencarian umum dimulai dengan permintaan POST yang mengembalikan referensi ke hasilnya. Ini menghasilkan hasilnya (ini baru dan dapat diambil dengan GET berikutnya). Hasil ini dapat bersifat hierarkis (referensi lebih lanjut dengan URI yang dapat Anda DAPATKAN), tentu saja, dan mungkin menggunakan kembali elemen pencarian sebelumnya, jika masuk akal untuk aplikasi tersebut.
Ngomong-ngomong, saya tahu orang melakukannya secara berbeda. Anda tidak perlu menjelaskan kepada saya betapa mudahnya melanggar REST.
sumber