Perlu diingat saya memiliki pemahaman yang belum sempurna tentang REST. Katakanlah saya punya URL ini:
http://api.animals.com/v1/dogs/1/
Dan sekarang, saya ingin membuat server membuat kulit anjing. Hanya server yang tahu cara melakukan ini. Katakanlah saya ingin menjalankannya pada pekerjaan CRON yang membuat anjing menggonggong setiap 10 menit selama sisa keabadian. Seperti apa panggilan itu? Saya agak ingin melakukan ini:
Permintaan URL:
ACTION http://api.animals.com/v1/dogs/1/
Di badan permintaan:
{"action":"bark"}
Sebelum Anda marah kepada saya karena membuat metode HTTP saya sendiri, bantu saya dan berikan saya ide yang lebih baik tentang bagaimana saya harus memanggil metode sisi server dengan cara yang tenang. :)
EDIT UNTUK KLARIFIKASI
Beberapa klarifikasi lebih lanjut tentang apa metode "kulit" tidak. Berikut adalah beberapa opsi yang dapat menghasilkan panggilan API terstruktur berbeda:
- kulit hanya mengirim email ke dog.email dan tidak mencatat apa pun.
- kulit mengirim email ke dog.email dan pertambahan dog.barkCount oleh 1.
- kulit membuat catatan "kulit" baru dengan rekaman kulit.timestamp ketika kulit itu terjadi. Ini juga menambah dog.barkCount dengan 1.
- kulit kayu menjalankan perintah sistem untuk menarik kode anjing versi terbaru dari Github. Kemudian mengirim pesan teks ke dog.owner mengatakan kepada mereka bahwa kode anjing baru sedang dalam produksi.
sumber
PATCH
bisa tepat. Saya menjelaskan mengapa menjelang akhir jawaban saya .Jawaban:
Mengapa bertujuan untuk desain yang tenang?
Prinsip RESTful membawa fitur yang membuat situs web mudah (bagi pengguna manusia acak untuk "berselancar") ke desain API layanan web , sehingga mudah digunakan oleh programmer. REST tidak baik karena REST, itu bagus karena itu bagus. Dan itu bagus terutama karena itu sederhana .
Kesederhanaan HTTP biasa (tanpa amplop SOAP dan
POST
layanan kelebihan-URI tunggal ), yang oleh sebagian orang disebut "kekurangan fitur" , sebenarnya merupakan kekuatan terbesarnya . Langsung dari kesalahan, HTTP meminta Anda untuk memiliki addressability dan statelessness : dua keputusan desain dasar yang menjaga HTTP scalable hingga situs mega saat ini (dan layanan mega).Tapi REST bukan bulletet perak: Kadang-kadang gaya RPC ("Remote Procedure Call" - seperti SOAP) mungkin sesuai , dan kadang-kadang kebutuhan lain didahulukan dari kebaikan Web. Ini baik Yang tidak kita sukai adalah kompleksitas yang tidak perlu . Terlalu sering programmer atau perusahaan membawa Layanan bergaya RPC untuk pekerjaan yang dapat ditangani oleh HTTP tua biasa. Efeknya adalah HTTP direduksi menjadi protokol transport untuk muatan XML yang sangat besar yang menjelaskan apa yang sebenarnya terjadi (bukan metode URI atau HTTP yang memberikan petunjuk tentang hal itu). Layanan yang dihasilkan terlalu rumit, tidak mungkin untuk di-debug, dan tidak akan berfungsi kecuali klien Anda memiliki pengaturan persis seperti yang diinginkan pengembang.
Cara yang sama kode Java / C # tidak bisa berorientasi objek, hanya menggunakan HTTP tidak membuat desain TENANG. Seseorang mungkin terjebak dalam ketergesaan berpikir tentang layanan mereka dalam hal tindakan dan metode jarak jauh yang harus dipanggil. Tidak heran ini sebagian besar akan berakhir dalam layanan RPC-Style (atau REST-RPC-hybrid). Langkah pertama adalah berpikir secara berbeda. Desain yang tenang dapat dicapai dengan banyak cara, salah satunya adalah dengan memikirkan aplikasi Anda dalam hal sumber daya, bukan tindakan:
Saya akan ambil contoh di bawah ini. (Aspek kunci lain dari REST adalah penggunaan HATEOAS - Saya tidak menyikatnya di sini, tapi saya membicarakannya dengan cepat di pos lain .)
Masalah desain pertama
Mari kita lihat desain yang diusulkan:
Pertama, kita seharusnya tidak mempertimbangkan membuat kata kerja HTTP baru (
ACTION
). Secara umum, ini tidak diinginkan karena beberapa alasan:ACTION
kata kerjanya?Sekarang mari kita pertimbangkan
POST
untuk menggunakan (saya akan membahas mengapa di bawah ini, ambil saja kata-kata saya sekarang):Ini mungkin OK ... tetapi hanya jika :
{"action":"bark"}
adalah sebuah dokumen; dan/v1/dogs/1/
adalah "pengolah dokumen" (seperti pabrik) URI. "Pemroses dokumen" adalah URI yang Anda "singkirkan" dan "lupakan" - prosesor dapat mengarahkan Anda ke sumber yang baru dibuat setelah "melempar". Misalnya URI untuk memposting pesan di layanan perantara pesan, yang, setelah posting akan mengarahkan Anda ke URI yang menunjukkan status pemrosesan pesan.Saya tidak tahu banyak tentang sistem Anda, tetapi saya sudah bertaruh keduanya tidak benar:
{"action":"bark"}
bukan dokumen , itu sebenarnya metode yang Anda coba untuk menyelinap masuk ke layanan; dan/v1/dogs/1/
URI merupakan "anjing" sumber daya (mungkin anjing denganid==1
) dan tidak prosesor dokumen.Jadi yang kita tahu sekarang adalah bahwa desain di atas tidak begitu tenang, tapi apa sebenarnya itu? Apa yang sangat buruk tentang itu? Pada dasarnya, itu buruk karena itu adalah URI yang kompleks dengan makna yang kompleks. Anda tidak dapat menyimpulkan apa pun darinya. Bagaimana seorang programmer mengetahui seekor anjing memiliki
bark
aksi yang dapat secara diam-diam dimasukkanPOST
ke dalamnya?Merancang panggilan API pertanyaan Anda
Jadi mari kita memotong ke pengejaran dan mencoba untuk merancang gonggongan itu dengan tenang dengan memikirkan sumber daya . Izinkan saya mengutip buku Restful Web Services :
Dengan mengikuti uraian di atas, kita dapat melihat bahwa
bark
dapat dimodelkan sebagai sub-sumber daya daridog
(karena abark
terkandung dalam seekor anjing, yaitu, kulit kayu "kulit kayu" oleh seekor anjing).Dari alasan itu kita sudah mendapat:
POST
/barks
, sub- sumber daya anjing:,/v1/dogs/1/barks
mewakilibark
"pabrik". URI itu unik untuk setiap anjing (karena di bawah/v1/dogs/{id}
).Sekarang setiap kasus daftar Anda memiliki perilaku tertentu.
1. kulit hanya mengirim email ke
dog.email
dan tidak merekam apa pun.Pertama, apakah menggonggong (mengirim email) tugas yang sinkron atau tidak sinkron? Kedua, apakah
bark
permintaan memerlukan dokumen apa pun (email, mungkin) atau kosong?1.1 kulit mengirim email ke
dog.email
dan tidak merekam apa-apa (sebagai tugas sinkron)Kasus ini sederhana. Panggilan ke
barks
sumber daya pabrik menghasilkan kulit kayu (e-mail terkirim) segera dan responsnya (jika OK atau tidak) segera diberikan:Saat merekam (perubahan) tidak ada,
200 OK
sudah cukup. Ini menunjukkan bahwa semuanya berjalan seperti yang diharapkan.1.2 kulit mengirim email ke
dog.email
dan tidak merekam apa-apa (sebagai tugas tidak sinkron)Dalam hal ini, klien harus memiliki cara untuk melacak
bark
tugas. Thebark
tugas kemudian harus menjadi sumber daya dengan itu sendiri URI .:Dengan cara ini, masing
bark
- masing dapat dilacak. Klien kemudian dapat mengeluarkan aGET
kebark
URI untuk mengetahui keadaan saat ini. Mungkin bahkan menggunakanDELETE
untuk membatalkannya.2. kulit kayu mengirim email ke
dog.email
dan kemudian bertambahdog.barkCount
1Yang ini bisa lebih sulit, jika Anda ingin memberi tahu klien bahwa
dog
sumber daya diubah:Dalam hal ini,
location
maksud header adalah memberi tahu klien bahwa ia harus melihatnyadog
. Dari HTTP RFC tentang303
:Jika tugas tidak sinkron,
bark
subresource diperlukan seperti1.2
situasinya dan303
harus dikembalikan padaGET .../barks/Y
saat tugas selesai.3. kulit membuat catatan "
bark
" baru denganbark.timestamp
merekam ketika kulit terjadi. Ini juga bertambahdog.barkCount
1.Di sini,
bark
itu dibuat karena permintaan, jadi statusnya201 Created
diterapkan.Jika pembuatannya tidak sinkron, maka
202 Accepted
diperlukan ( seperti yang dikatakan HTTP RFC ).Stempel waktu yang disimpan adalah bagian dari
bark
sumber daya dan dapat diambil denganGET
itu. Anjing yang diperbarui dapat "didokumentasikan" diGET dogs/X/barks/Y
dalamnya juga.4. kulit kayu menjalankan perintah sistem untuk menarik kode anjing versi terbaru dari Github. Kemudian mengirim pesan teks untuk
dog.owner
memberi tahu mereka bahwa kode anjing baru dalam produksi.Kata-kata yang satu ini rumit, tetapi cukup banyak tugas asinkron yang sederhana:
Klien kemudian akan mengeluarkan
GET
s untuk/v1/dogs/1/barks/a65h44
mengetahui keadaan saat ini (jika kode itu ditarik, itu e-mail dikirim ke pemilik dan semacamnya). Setiap kali anjing berubah, a303
dapat diterapkan.Membungkus
Mengutip Roy Fielding :
Dalam contoh di atas,
POST
dirancang secara seragam. Itu akan membuat anjing "bark
". Itu tidak aman (artinya kulit kayu memiliki efek pada sumber daya), atau idempoten (setiap permintaan menghasilkan yang barubark
), yang cocok denganPOST
kata kerja dengan baik.Seorang programmer akan tahu: a
POST
tobarks
yields abark
. Kode status respons (juga dengan entitas-badan dan header bila perlu) melakukan pekerjaan menjelaskan apa yang berubah dan bagaimana klien dapat dan harus melanjutkan.Catatan: Sumber utama yang digunakan adalah: " Restful Web Services " buku, HTTP RFC dan blog Roy Fielding .
Edit:
Pertanyaan dan dengan demikian jawabannya telah sedikit berubah sejak pertama kali dibuat. Pertanyaan awal ditanyakan tentang desain URI seperti:
Di bawah ini adalah penjelasan mengapa itu bukan pilihan yang baik:
Bagaimana klien memberi tahu server APA YANG HARUS DILAKUKAN dengan data adalah informasi metode .
BAGIAN yang dari data [klien ingin server] untuk beroperasi adalah informasi pelingkupan .
Sebagai contoh, ambil Google URI
http://www.google.com/search?q=DOG
. Di sana, informasi metode adalahGET
dan informasi pelingkupannya/search?q=DOG
.Singkat cerita:
Dan aturan praktisnya:
Anda dapat meletakkan "kulit" "tindakan" di URL (atau di badan-entitas) dan gunakan
POST
. Tidak masalah di sana, ini berfungsi, dan mungkin cara paling sederhana untuk melakukannya, tetapi ini tidak tenang .Untuk menjaga layanan Anda tetap tenang, Anda mungkin harus mengambil langkah mundur dan memikirkan apa yang benar-benar ingin Anda lakukan di sini (efek apa yang akan terjadi pada sumber daya).
Saya tidak dapat berbicara tentang kebutuhan bisnis spesifik Anda, tetapi izinkan saya memberi Anda sebuah contoh: Pertimbangkan layanan pemesanan yang tenang di mana pesanan berada di URI seperti
example.com/order/123
.Sekarang katakanlah kita ingin membatalkan pesanan, bagaimana kita akan melakukannya? Orang mungkin tergoda untuk berpikir bahwa itu adalah "pembatalan" "tindakan" dan mendesainnya sebagai
POST example.com/order/123?do=cancel
.Itu tidak tenang, seperti yang kita bicarakan di atas. Sebagai gantinya, kami mungkin
PUT
representasi baru dariorder
dengancanceled
elemen yang dikirim ketrue
:Dan itu saja. Jika pesanan tidak dapat dibatalkan, kode status tertentu dapat dikembalikan. (Desain sub-sumber daya, seperti
POST /order/123/canceled
dengan entitas-badantrue
mungkin, untuk kesederhanaan, juga tersedia.)Dalam skenario spesifik Anda, Anda dapat mencoba sesuatu yang serupa. Dengan begitu, saat anjing menggonggong, misalnya,
GET
at/v1/dogs/1/
dapat memasukkan informasi itu (misalnya<barking>true</barking>
) . Atau ... jika itu terlalu rumit, kendurkan persyaratan RESTful Anda dan ikutiPOST
.Memperbarui:
Saya tidak ingin membuat jawaban terlalu besar, tetapi perlu beberapa saat untuk membiasakan mengekspos algoritma ( aksi ) sebagai satu set sumber daya. Alih-alih berpikir dalam hal tindakan ( "melakukan pencarian tempat di peta" ), orang perlu berpikir dalam hal hasil dari tindakan itu ( "daftar tempat di peta yang cocok dengan kriteria pencarian" ).
Anda mungkin menemukan diri Anda kembali ke langkah ini jika Anda menemukan bahwa desain Anda tidak sesuai dengan antarmuka seragam HTTP.
Variabel kueri adalah pelingkupan informasi , tetapi tidak menunjukkan sumber daya baru (
/post?lang=en
jelas sumber daya yang sama dengan/post?lang=jp
, hanya representasi yang berbeda). Sebaliknya, mereka digunakan untuk menyampaikan status klien (seperti?page=10
, sehingga status tidak disimpan di server;?lang=en
juga merupakan contoh di sini) atau memasukkan parameter ke sumber daya algoritmik (/search?q=dogs
,/dogs?code=1
). Sekali lagi, bukan sumber daya yang berbeda.Properti (metode) kata kerja HTTP:
Poin jelas lainnya yang ditampilkan
?action=something
dalam URI adalah tidak TETAP, adalah properti dari kata kerja HTTP:GET
danHEAD
aman (dan idempoten);PUT
danDELETE
hanya idempoten;POST
bukan keduanya.Keamanan : Permintaan
GET
atauHEAD
permintaan adalah permintaan untuk membaca beberapa data, bukan permintaan untuk mengubah status server apa pun. Klien dapat membuatGET
atauHEAD
meminta 10 kali dan itu sama dengan membuatnya sekali, atau tidak pernah membuatnya sama sekali .Idempoten : Operasi idempoten di salah satu yang memiliki efek yang sama apakah Anda menerapkannya sekali atau lebih dari sekali (dalam matematika, mengalikan dengan nol adalah idempoten). Jika Anda
DELETE
sumber daya sekali, menghapus lagi akan memiliki efek yang sama (sumber dayaGONE
sudah ada).POST
tidak aman atau idempoten. Membuat duaPOST
permintaan yang identik dengan sumber daya 'pabrik' mungkin akan menghasilkan dua sumber daya bawahan yang mengandung informasi yang sama. Dengan kelebihan beban (metode dalam URI atau entitas-tubuh)POST
, semua taruhan dimatikan.Kedua properti ini penting untuk keberhasilan protokol HTTP (melalui jaringan yang tidak dapat diandalkan!): Berapa kali Anda memperbarui (
GET
) halaman tanpa menunggu sampai sepenuhnya dimuat?Membuat tindakan dan menempatkannya di URL dengan jelas melanggar kontrak metode HTTP. Sekali lagi, teknologi memungkinkan Anda, Anda bisa melakukannya, tetapi itu bukan desain yang tenang.
sumber
POST
dirancang untuk "menyediakan blok data ... untuk proses penanganan data" . Tampaknya banyak orang membedakan sumber daya dari tindakan, tetapi benar-benar tindakan hanyalah jenis sumber daya.POST
"menyediakan blok data ... untuk proses penanganan data", tetapi perbedaannya adalah, blok data , bukan blok data dan prosedur (tindakan, metode, perintah) untuk menjadi dieksekusi pada saat itu. ItuPOST
overloading, danPOST
overloading adalah desain RPC-Style, bukan RESTful.Saya menjawab sebelumnya , tetapi jawaban ini bertentangan dengan jawaban lama saya dan mengikuti strategi yang jauh berbeda untuk mencapai solusi. Ini menunjukkan bagaimana permintaan HTTP dibangun dari konsep yang mendefinisikan REST dan HTTP. Ini juga menggunakan
PATCH
bukanPOST
atauPUT
.Ia melewati batasan REST, lalu komponen HTTP, lalu solusi yang memungkinkan.
BERISTIRAHAT
REST adalah serangkaian kendala yang dimaksudkan untuk diterapkan pada sistem hypermedia terdistribusi untuk membuatnya scalable. Bahkan untuk membuatnya masuk akal dalam konteks mengendalikan suatu tindakan dari jarak jauh, Anda harus berpikir untuk mengendalikan suatu tindakan dari jarak jauh sebagai bagian dari sistem hypermedia terdistribusi - bagian dari sistem untuk menemukan, melihat, dan mengubah informasi yang saling berhubungan. Jika itu lebih banyak masalah daripada nilainya, maka mungkin tidak baik untuk mencoba membuatnya Tenang. Jika Anda hanya menginginkan "panel kontrol" ketik GUI pada klien yang dapat memicu tindakan pada server melalui port 80, maka Anda mungkin menginginkan antarmuka RPC sederhana seperti JSON-RPC melalui permintaan / tanggapan HTTP atau WebSocket.
Tetapi REST adalah cara berpikir yang menarik dan contoh dalam pertanyaan tersebut adalah mudah untuk dimodelkan dengan antarmuka RESTful, jadi mari kita hadapi tantangan untuk bersenang-senang dan untuk pendidikan.
REST didefinisikan oleh empat batasan antarmuka:
Anda bertanya bagaimana Anda bisa mendefinisikan antarmuka, memenuhi batasan-batasan ini, di mana satu komputer memberitahu komputer lain untuk membuat kulit anjing. Khususnya, Anda ingin antarmuka Anda menjadi HTTP, dan Anda tidak ingin membuang fitur yang membuat HTTP RESTful saat digunakan sebagaimana dimaksud.
Mari kita mulai dengan kendala pertama: identifikasi sumber daya .
Jadi seekor anjing adalah sumber daya. Itu perlu diidentifikasi.
Anda membuat model seekor anjing dengan mengambil satu set pengidentifikasi dan representasi dan mengatakan mereka semua terkait satu sama lain pada waktu tertentu. Untuk sekarang, mari gunakan pengidentifikasi "anjing # 1". Itu membawa kita ke kendala kedua dan ketiga: representasi sumber daya dan deskripsi diri .
Berikut ini adalah urutan byte yang menangkap keadaan anjing yang dimaksud, yaitu representasi yang kami ingin dikaitkan dengan pengidentifikasi "anjing # 1" (perhatikan bahwa itu hanya mewakili bagian dari keadaan karena tidak memperhatikan nama anjing, kesehatan , atau bahkan menggonggong masa lalu):
Seharusnya melekat pada metadata yang menggambarkannya. Metadata ini mungkin berguna:
Akhirnya, mari kita lihat batasan keempat: HATEOAS .
Dalam antarmuka yang tenang, klien menerima representasi sumber daya untuk mengetahui bagaimana ia harus menerima atau mengirim representasi. Harus ada representasi di suatu tempat dalam aplikasi yang darinya klien dapat mengetahui cara menerima atau mengirim semua representasi yang seharusnya dapat diterima atau dikirim, bahkan jika ia mengikuti rantai representasi untuk sampai pada informasi itu. Ini tampaknya cukup sederhana:
Klien meminta representasi sumber daya yang diidentifikasi sebagai beranda; sebagai tanggapan, ia mendapat representasi yang berisi pengidentifikasi setiap anjing yang mungkin diinginkan klien. Klien mengekstraksi pengidentifikasi darinya dan menanyakan layanan bagaimana ia dapat berinteraksi dengan anjing yang diidentifikasi, dan layanan mengatakan klien dapat mengirim pernyataan bahasa Inggris yang menggambarkan bagian dari kondisi anjing yang dimaksud. Kemudian klien mengirim pernyataan seperti itu dan menerima pesan sukses atau pesan kesalahan.
HTTP
HTTP menerapkan batasan REST sebagai berikut:
identifikasi sumber daya : URI
representasi sumber daya : entitas-badan
deskripsi-diri : metode atau kode status, tajuk, dan kemungkinan bagian-bagian dari entitas-badan (mis. URI dari skema XML)
HATEOAS : hyperlink
Anda telah memutuskan
http://api.animals.com/v1/dogs/1
sebagai URI. Mari kita asumsikan klien mendapatkan ini dari beberapa halaman di situs.Mari kita gunakan entitas-badan ini (nilai
next
timestamp; nilai0
sarana 'saat permintaan ini diterima'):Sekarang kita membutuhkan suatu metode. PATCH cocok dengan deskripsi "bagian dari negara yang dituju" yang kami putuskan:
Dan beberapa tajuk:
Untuk menunjukkan bahasa entitas-tubuh:
Content-Type: application/json
Untuk memastikan itu hanya terjadi sekali:
If-Unmodified-Since: <date/time this was first sent>
Dan kami memiliki permintaan:
Jika berhasil, klien harus menerima
204
kode status sebagai respons, atau205
jika representasi/v1/dogs/1/
telah berubah untuk mencerminkan jadwal menggonggong baru.Pada kegagalan, seharusnya menerima
403
dan membantu pesan mengapa.Tidaklah penting untuk REST bagi layanan untuk merefleksikan jadwal kulit kayu dalam representasi sebagai tanggapan
GET /v1/dogs/1/
, tetapi akan lebih masuk akal jika perwakilan JSON menyertakan ini:Perlakukan pekerjaan cron sebagai detail implementasi yang disembunyikan server dari antarmuka. Itulah keindahan antarmuka generik. Klien tidak harus tahu apa yang dilakukan server di balik layar; yang perlu diperhatikan adalah layanan memahami dan merespons perubahan status yang diminta.
sumber
Kebanyakan orang menggunakan POST untuk tujuan ini. Sangat tepat untuk melakukan "operasi apa pun yang tidak aman atau tidak ramah ketika tidak ada metode HTTP lain yang sesuai".
API seperti XMLRPC menggunakan POST untuk memicu tindakan yang dapat menjalankan kode arbitrer. "Tindakan" termasuk dalam data POST:
Contoh RPC diberikan untuk menunjukkan bahwa POST adalah pilihan konvensional kata kerja HTTP untuk metode sisi server. Inilah pemikiran Roy Fielding pada POST - ia cukup banyak mengatakan itu tenang untuk menggunakan metode HTTP seperti yang ditentukan.
Perhatikan bahwa RPC itu sendiri tidak terlalu tenang karena tidak berorientasi sumber daya. Tetapi jika Anda membutuhkan kewarganegaraan, caching, atau layering, tidak sulit untuk melakukan transformasi yang tepat. Lihat http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ untuk contoh.
sumber
POST api.animals.com/v1/dogs1?action=bark
/RPC2
tidak melakukan apa pun untuk mengidentifikasi sumber daya - ini mengidentifikasi teknologi server. Alih-alih, ini digunakanmethodName
untuk mencoba 'mengidentifikasi' sumber daya '- tetapi bahkan kemudian, itu tidak mendapat manfaat dari perbedaan kata benda / kata kerja; satu-satunya 'kata kerja' di sini adalahmethodCall
. Ini seperti 'do state-name-retrieval' dan bukannya 'take-state-name' - yang terakhir jauh lebih masuk akal.POST
adalah metode HTTP yang dirancang untukMetode sisi server yang menangani tindakan yang tidak dipetakan CRUD adalah apa yang dimaksudkan oleh Roy Fielding dengan REST, jadi Anda hebat di sana, dan itulah sebabnya
POST
dibuat menjadi non-idempoten.POST
akan menangani sebagian besar pengiriman data ke metode sisi server untuk memproses informasi.Yang mengatakan, dalam skenario menggonggong anjing Anda, jika Anda ingin menggonggong sisi server dilakukan setiap 10 menit, tetapi untuk beberapa alasan perlu pemicu berasal dari klien,
PUT
akan melayani tujuan lebih baik, karena idempotensinya. Ya, benar-benar berdasarkan skenario ini, tidak ada risiko yang jelas dari beberapa permintaan POST yang menyebabkan anjing Anda mengeong, tetapi toh itulah tujuan dari dua metode yang serupa. Jawaban saya untuk pertanyaan SO yang serupa mungkin bermanfaat bagi Anda.sumber
PUT
URL merujuk pada apa yang harus diganti oleh konten klien danPOST
URL mengacu pada apa yang harus memproses konten klien seperti yang diinginkan.Jika kita menganggap Barking adalah sumber daya dalam / dependen / sub di mana konsumen dapat bertindak, maka kita dapat mengatakan:
gonggongan anjing nomor 1
mengembalikan cap waktu kulit terakhir
tidak berlaku! jadi abaikan saja.
sumber
/v1/dogs/1/bark
untuk menjadi sumber daya per se , danPOST
menjadi deskripsi tentang bagaimana keadaan internal sumber daya itu harus berubah. Saya menemukan bahwa lebih masuk akal untuk mempertimbangkan/v1/dogs/1/
sebagai sumber daya dan menunjukkan dalam entitas-badan bahwa ia harus menggonggong.Revisi sebelumnya atas beberapa jawaban menyarankan Anda menggunakan RPC. Anda tidak perlu untuk melihat ke RPC seperti ini sangat mungkin untuk melakukan apa yang Anda inginkan sementara mengikuti kendala REST.
Pertama, jangan letakkan parameter tindakan di URL. URL menentukan apa yang Anda terapkan tindakan, dan parameter permintaan adalah bagian dari URL. Itu harus dianggap sepenuhnya sebagai kata benda.
http://api.animals.com/v1/dogs/1/?action=bark
adalah sumber yang berbeda - kata benda yang berbeda - untukhttp://api.animals.com/v1/dogs/1/
. [nb Penanya telah menghapus?action=bark
URI dari pertanyaan.] Misalnya, bandingkanhttp://api.animals.com/v1/dogs/?id=1
denganhttp://api.animals.com/v1/dogs/?id=2
. Sumber daya berbeda, hanya dibedakan oleh string kueri. Jadi tindakan permintaan Anda, kecuali jika itu berhubungan langsung dengan jenis metode yang ada tanpa badan (TRACE, OPTIONS, HEAD, GET, DELETE, dll) harus didefinisikan dalam badan permintaan.Selanjutnya, putuskan apakah tindakan itu " idempoten ", artinya tindakan itu dapat diulang tanpa efek yang merugikan (lihat paragraf berikutnya untuk penjelasan lebih lanjut). Misalnya, menetapkan nilai ke true dapat diulang jika klien tidak yakin bahwa efek yang diinginkan terjadi. Mereka mengirim permintaan lagi dan nilainya tetap benar. Menambahkan 1 ke angka bukanlah idempoten. Jika klien mengirim perintah Add1, tidak yakin itu berhasil, dan mengirimkannya lagi, apakah server menambahkan satu atau dua? Setelah Anda menentukan itu, Anda berada dalam posisi yang lebih baik untuk memilih di antara
PUT
danPOST
untuk metode Anda.Idempoten berarti permintaan dapat diulang tanpa mengubah hasilnya. Efek ini tidak termasuk pencatatan dan aktivitas admin server lainnya. Menggunakan contoh pertama dan kedua Anda, mengirim dua email ke orang yang sama menghasilkan keadaan yang berbeda dari mengirim satu email (penerima memiliki dua di kotak masuk mereka, yang mereka anggap sebagai spam), jadi saya pasti akan menggunakan POST untuk itu . Jika barkCount dalam contoh 2 dimaksudkan untuk dilihat oleh pengguna API Anda atau memengaruhi sesuatu yang terlihat oleh klien, maka itu juga merupakan sesuatu yang akan membuat permintaan tersebut menjadi non-idempoten. Jika hanya untuk dilihat oleh Anda maka itu dianggap sebagai pendataan server dan harus diabaikan ketika menentukan idempotentcy.
Terakhir, tentukan apakah tindakan yang ingin Anda lakukan dapat diharapkan berhasil segera atau tidak. BarkDog adalah tindakan yang cepat selesai. RunMarathon tidak. Jika tindakan Anda lambat, pertimbangkan untuk mengembalikan a
202 Accepted
, dengan URL di badan respons agar pengguna dapat polling untuk melihat apakah tindakan itu selesai. Atau, minta pengguna POST ke daftar URL suka/marathons-in-progress/
dan kemudian ketika tindakan dilakukan, mengarahkan mereka dari URL ID sedang berlangsung ke/marathons-complete/
URL.Untuk kasus-kasus tertentu # 1 dan # 2, saya akan meminta server host antrian, dan klien memposting batch alamat untuk itu. Tindakannya bukan SendEmails, tetapi sesuatu seperti AddToDispatchQueue. Server kemudian dapat polling antrian untuk melihat apakah ada alamat email yang menunggu, dan mengirim email jika ada. Ini kemudian memperbarui antrian untuk menunjukkan bahwa tindakan yang tertunda sekarang telah dilakukan. Anda akan memiliki URI lain yang menunjukkan kepada klien keadaan antrian saat ini. Untuk menghindari pengiriman ganda email, server juga dapat menyimpan log yang telah dikirimi email ini, dan memeriksa setiap alamat yang menentangnya untuk memastikan tidak pernah mengirim dua ke alamat yang sama, bahkan jika Anda POST daftar yang sama dua kali untuk antrian.
Ketika memilih URI untuk apa pun, coba pikirkan itu sebagai hasilnya, bukan tindakan. Misalnya
google.com/search?q=dogs
menunjukkan hasil pencarian untuk kata "anjing". Tidak perlu melakukan pencarian.Kasus # 3 dan # 4 dari daftar Anda juga bukan tindakan idempoten. Anda menyarankan bahwa berbagai efek yang disarankan dapat memengaruhi desain API. Dalam keempat kasus saya akan menggunakan API yang sama, karena keempatnya mengubah "negara dunia."
sumber
Lihat jawaban baru saya - ini bertentangan dengan yang ini dan menjelaskan REST dan HTTP dengan lebih jelas dan akurat.
Berikut adalah rekomendasi yang kebetulan tenang tetapi tentu saja bukan satu-satunya pilihan. Untuk mulai menggonggong ketika layanan menerima permintaan:
token
adalah nomor sewenang-wenang yang mencegah gonggongan redundan tidak peduli berapa kali permintaan ini dikirim.next
menunjukkan waktu kulit berikutnya; nilai0
sarana 'ASAP'.Setiap kali Anda
GET /v1/dogs/1/bark-schedule
, Anda harus mendapatkan sesuatu seperti ini, di mana t adalah waktu dari kulit lalu dan u adalah t + 10 menit:{"last": t, "next": u}
Saya sangat menyarankan Anda menggunakan URL yang sama untuk meminta kulit kayu yang Anda gunakan untuk mencari tahu tentang kondisi menggonggong anjing saat ini. Ini tidak penting untuk REST, tetapi menekankan tindakan memodifikasi jadwal.
Kode status yang sesuai mungkin 205 . Saya membayangkan klien yang melihat jadwal saat ini,
POST
s ke URL yang sama untuk mengubahnya, dan diinstruksikan oleh layanan untuk memberikan jadwal tampilan kedua untuk membuktikan bahwa itu telah diubah.Penjelasan
BERISTIRAHAT
Lupakan HTTP sejenak. Sangat penting untuk memahami bahwa sumber daya adalah fungsi yang membutuhkan waktu sebagai input dan mengembalikan set yang berisi pengidentifikasi dan representasi . Mari kita sederhanakan untuk: suatu sumber daya adalah seperangkat R pengidentifikasi dan representasi; R dapat berubah - anggota dapat ditambahkan, dihapus, atau dimodifikasi. (Meskipun itu buruk, desain stabil untuk menghapus atau mengubah pengenal.) Kita mengatakan sebuah identifier yang merupakan elemen dari R mengidentifikasi R , dan bahwa representasi yang merupakan elemen dari R mewakili R .
Katakanlah R adalah seekor anjing. Anda kebetulan mengidentifikasi R sebagai
/v1/dogs/1
. (Arti/v1/dogs/1
adalah anggota R .) Itu hanya salah satu dari banyak cara yang bisa mengidentifikasi R . Anda juga dapat mengidentifikasi R sebagai/v1/dogs/1/x-rays
dan sebagai/v1/rufus
.Bagaimana Anda mewakili R ? Mungkin dengan foto. Mungkin dengan satu set sinar-X. Atau mungkin dengan indikasi tanggal dan waktu ketika R terakhir menyalak. Tetapi ingat bahwa ini semua adalah representasi dari sumber yang sama .
/v1/dogs/1/x-rays
adalah pengidentifikasi dari sumber daya yang sama yang diwakili oleh jawaban untuk pertanyaan "kapan R kulit terakhir?"HTTP
Representasi berganda dari sumber daya tidak terlalu berguna jika Anda tidak bisa merujuk ke yang Anda inginkan. Karena itulah HTTP berguna: memungkinkan Anda menghubungkan pengidentifikasi ke representasi . Artinya, ini adalah cara bagi layanan untuk menerima URL dan memutuskan perwakilan mana yang akan dilayani kepada klien.
Setidaknya, itulah yang
GET
dilakukannya.PUT
pada dasarnya adalah kebalikan dariGET
: AndaPUT
representasi r di URL jika Anda ingin agarGET
permintaan di masa depan untuk mengembalikan r , dengan beberapa terjemahan yang mungkin seperti JSON ke HTML.POST
adalah cara yang lebih longgar untuk memodifikasi representasi. Bayangkan ada logika tampilan dan logika modifikasi yang merupakan rekan satu sama lain - keduanya sesuai dengan URL yang sama. Permintaan POST adalah permintaan untuk logika modifikasi untuk memproses informasi dan memodifikasi representasi apa pun (bukan hanya representasi yang terletak dengan URL yang sama) sesuai dengan keinginan layanan. Perhatikan paragraf ketiga setelah 9,6 PUT : Anda tidak mengganti barang di URL dengan konten baru; Anda meminta sesuatu di URL untuk memproses beberapa informasi dan merespons dengan cerdas dalam bentuk representasi informatif.Dalam kasus kami, kami meminta logika modifikasi di
/v1/dogs/1/bark-schedule
(yang merupakan lawan logika tampilan yang memberi tahu kami kapan salak terakhir dan kapan salak berikutnya) untuk memproses informasi kami dan memodifikasi beberapa representasi yang sesuai. Menanggapi masa depanGET
, logika tampilan yang sesuai dengan URL yang sama akan memberi tahu kami bahwa anjing itu sekarang menggonggong seperti yang kita inginkan.Pikirkan pekerjaan cron sebagai detail implementasi. Penawaran HTTP dalam melihat dan memodifikasi representasi. Mulai sekarang, layanan akan memberi tahu klien kapan anjing menggonggong terakhir dan kapan akan menggonggong berikutnya. Dari perspektif layanan, itu jujur karena masa-masa itu sesuai dengan pekerjaan cron masa lalu dan yang direncanakan.
sumber
REST adalah standar yang berorientasi sumber daya, ini bukan tindakan yang didorong seperti RPC.
Jika Anda ingin server Anda menggonggong , Anda harus melihat ke berbagai ide seperti JSON-RPC , atau ke komunikasi websockets.
Setiap mencoba untuk tetap tenang akan gagal dalam pendapat saya: Anda bisa mengeluarkan
POST
denganaction
parameter, Anda tidak menciptakan sumber daya baru tetapi karena Anda mungkin memiliki efek samping, Anda lebih aman.sumber
POST
dirancang untuk "menyediakan blok data ... untuk proses penanganan data" . Tampaknya banyak orang membedakan sumber daya dari tindakan, tetapi benar-benar tindakan hanyalah jenis sumber daya. Memanggil sumber aksi di server masih berupa antarmuka yang seragam, dapat disimpan dalam cache, modular, dan dapat diskalakan. Itu juga tanpa kewarganegaraan, tetapi itu bisa dilanggar jika klien dirancang untuk mengharapkan respons. Tetapi memanggil "void method" di server adalah apa yang dimaksud Roy Fielding dengan REST .