REST API DESIGN - Mendapatkan sumber daya melalui REST dengan parameter berbeda tetapi pola url yang sama

92

Saya punya pertanyaan terkait dengan desain url REST. Saya menemukan beberapa posting yang relevan di sini: Representasi RESTful yang berbeda dari resource yang sama dan di sini: RESTful url to GET resource oleh bidang yang berbeda tetapi tanggapannya tidak cukup jelas tentang apa itu praktik terbaik dan mengapa. Berikut contohnya.

Saya memiliki url REST untuk mewakili sumber daya "pengguna". Saya bisa MENDAPATKAN pengguna dengan id atau dengan alamat email tetapi representasi URL tetap sama untuk keduanya. Melalui banyak blog dan buku, saya melihat bahwa orang telah melakukan ini dengan berbagai cara. Sebagai contoh

baca praktik ini di buku dan di stackoverflow (sepertinya saya tidak dapat menemukan tautannya lagi)

GET /users/id={id}
GET /users/email={email}

baca latihan ini di banyak blog

GET /users/{id}
GET /users/email/{email}

Parameter kueri biasanya digunakan untuk memfilter hasil sumber daya yang diwakili oleh url, tetapi saya telah melihat praktik ini digunakan juga

GET /users?id={id}
GET /users?email={email}

Pertanyaan saya adalah, dari semua praktik ini, mana yang paling masuk akal bagi pengembang yang mengonsumsi api dan mengapa? Saya percaya tidak ada aturan yang ditetapkan dalam hal desain url REST dan konvensi penamaan, tapi saya hanya ingin tahu rute mana yang harus saya ambil untuk membantu pengembang lebih memahami apis.

Semua bantuan dihargai!

shahshi15
sumber
1
Saya tahu ini agak tua tetapi mencari sumber daya serupa Saya tersandung pada pertanyaan ini dan yang Anda cari. Saya percaya inilah stackoverflow.com/a/9743414/468327
Joel Berger

Jawaban:

104

Menurut pengalaman saya, GET /users/{id} GET /users/email/{email}adalah pendekatan yang paling umum. Saya juga mengharapkan metode untuk mengembalikan 404 Not Found jika pengguna tidak ada dengan yang disediakan idatau email. Saya juga tidak akan terkejut melihatnya GET /users/id/{id}(meskipun menurut saya, itu mubazir).

Komentar tentang pendekatan lain

  1. GET /users/id={id} GET /users/email={email}
    • Saya rasa saya belum pernah melihat ini, dan jika saya melihatnya, itu akan sangat membingungkan. Ini hampir seperti mencoba meniru parameter kueri dengan parameter jalur.
  2. GET /users?id={id} GET /users?email={email}
    • Saya pikir Anda tepat sasaran ketika Anda menyebutkan menggunakan parameter kueri untuk pemfilteran.
    • Akan pernah masuk akal untuk memanggil sumber daya ini dengan baik sebuah iddan email(misalnya GET /users?id={id}&email={email})? Jika tidak, saya tidak akan menggunakan metode sumber daya tunggal seperti ini.
    • Saya mengharapkan metode ini untuk mengambil daftar pengguna dengan parameter kueri opsional untuk pemfilteran, tetapi saya tidak berharap id, emailatau pengenal unik apa pun berada di antara parameter. Misalnya: GET /users?status=BANNEDmungkin menampilkan daftar pengguna yang dilarang.

Lihat jawaban ini dari pertanyaan terkait.

DannyMo
sumber
Terima kasih atas masukannya. Sebenarnya kamu benar. Sepertinya saya membaca # 1 dalam buku "RESTful java with Jax-rs" tapi agak di luar konteks. Tapi saya ingat dengan sangat jelas membaca itu sebagai jawaban untuk salah satu pertanyaan tentang stackoverflow itu sendiri (percayalah ketika saya mengatakan saya berusaha sangat keras untuk menemukan tautan itu untuk membuktikan kepada kolega saya juga :)) dan # 2 persis seperti saya mencari. Beberapa umpan balik tentang desain. Terima kasih!
shahshi15
PS: Saya tidak yakin jika posting ini melanggar aturan di sini tapi Anda mungkin bisa menjelaskan salah satu pertanyaan saya yang lain juga? silahkan? :) stackoverflow.com/questions/20508008/…
shahshi15
hanya untuk mengklarifikasi tentang pernyataan redundansi Anda /users/id/{id}, ini memungkinkan fungsionalitas yang diperluas, cukup memungkinkan untuk mengakses satu sumber daya melalui beberapa pengenal (id, guid, name). juga menjawab di sini
Daniel Dubovski
4
Jawaban saya adalah bahwa cara yang tepat untuk mereferensikan Pengguna tertentu, misalnya, adalah / users / {id}. Jika Anda ingin menemukan pengguna dengan alamat email tertentu yang bukan merupakan pengenal unik untuk pengguna yang akan saya lakukan / users? Email = {email} karena ini adalah cara untuk memfilter kumpulan pengguna, bukan mengidentifikasi satu sumber daya tertentu dengan sumbernya pengenal sebagai / users / {id} adalah.
Kevin M
Jawaban yang bagus! Jempol untuk itu. Satu-satunya hal yang saya sarankan untuk dilakukan adalah juga untuk mengubah API Anda sedikit karena REST harus berpusat pada nama sehingga pemetaan sumber daya Anda harus seperti: GET /user/1234dan bukanGET /users/123
Sammy
38

Melihat ini secara pragmatis, Anda memiliki sekumpulan pengguna:

/users   # this returns many

Setiap pengguna memiliki lokasi sumber daya khusus:

/users/{id}    # this returns one

Anda juga memiliki sejumlah cara untuk mencari pengguna:

/users?email={email}
/users?name=*bob*

Karena ini semua adalah parameter kueri untuk / pengguna, mereka semua harus mengembalikan daftar .. meskipun itu adalah daftar 1.

Saya menulis posting blog tentang desain API RESTful pragmatis di sini yang membahas hal ini, antara lain, di sini: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

Vinay Sahni
sumber
Terima kasih atas balasannya vinay. Tetapi jika kita memikirkan ini dalam perspektif lain, {email} seperti {id} SELALU akan mengembalikan satu hasil. Jika kita benar-benar mencari, mengapa tidak menggunakan? Id = {id} dan juga untuk email? Saya bertanya-tanya apakah ada cara untuk tetap konsisten. PS: baru untuk stackoverflow, tidak tahu saya bisa satu hanya satu jawaban. Tapi terima kasih atas balasan Anda! Menghargai itu. Mungkin Anda dapat membantu saya dengan yang ini juga: stackoverflow.com/questions/20508008/…
shahshi15
7
Di sinilah aspek "desain" dari desain API berperan. Sumber daya Anda harus memiliki lokasi khusus. Dimana lokasinya? Apakah lokasi menurut id? Jika demikian, maka Anda tidak "mencari" berdasarkan id, Anda "mendapatkan" berdasarkan id. Tapi Anda mencari dengan yang lainnya. Tentu saja, tidak ada aturan baku di sini. Ini hanya perspektif :)
Vinay Sahni
6
Saya juga berpendapat bahwa dengan cara ini API Anda lebih stabil. Anda benar-benar tahu bahwa id Anda unik tetapi apakah Anda benar-benar yakin dengan alamat emailnya? Meskipun unik, mungkin tidak permanen karena pengguna dapat mengubahnya. Jadi / users? Email = {email} memperjelas bahwa ini memang kueri dan bukan akses ke sumber daya dengan pengenal permament.
lex82
Saya yakin ini adalah jawaban yang lebih tepat. Memfilter koleksi menurut alamat email bisa menjadi berbasis karakter pengganti sehingga tidak selalu mengembalikan hanya satu hasil.
Kevin M
@VinaySahni Apa pendapat Anda tentang pola seperti: /user?by=email&email="[email protected] "/ user? By = id & id =" xashkhx "/ users? FilterA =" a "& filterB =" b "(jamak untuk banyak pengguna)
Shasak
2

Tentang sumber daya pengguna

di jalur /usersAnda akan selalu mendapatkan kumpulan sumber daya pengguna yang dikembalikan.

di jalan /users/[user_id]Anda dapat mengharapkan beberapa hal terjadi:

  1. Anda harus mendapatkan sumber daya tunggal yang mewakili sumber daya pengguna dengan pengenalnya [user_id] atau
  2. respons 404 tidak ditemukan jika tidak ada pengguna dengan id [user_id] atau
  3. 401 terlarang jika Anda tidak diizinkan untuk mengakses sumber daya pengguna yang diminta.

Setiap singleton secara unik diidentifikasi oleh jalur dan pengenalnya dan Anda menggunakannya untuk menemukan sumber daya. Tidak mungkin menggunakan beberapa jalur untuk singleton.

Anda dapat membuat kueri jalur /usersdengan parameter kueri ( GETParameter). Ini akan mengembalikan koleksi dengan pengguna yang memenuhi kriteria yang diminta. Koleksi yang dikembalikan harus berisi sumber daya pengguna, semua dengan jalur sumber daya pengidentifikasi dalam respons.

Parameter dapat berupa bidang apa pun yang ada di sumber daya koleksi; firstName, lastName,id

Tentang email

Email dapat berupa sumber daya atau properti / bidang sumber daya pengguna.

- Email sebagai milik pengguna:

Jika bidang adalah milik pengguna, tanggapan pengguna akan terlihat seperti ini:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: '[email protected]'
  ...
}

Ini berarti tidak ada endpoint khusus untuk email, tapi sekarang Anda dapat menemukan pengguna dengan email dengan mengirimkan permintaan berikut: /[email protected]. Yang (dengan asumsi email unik untuk pengguna) akan mengembalikan koleksi dengan satu item pengguna yang cocok dengan email tersebut.

- Email sebagai sumber:

Tetapi jika email dari pengguna juga merupakan sumber daya. Kemudian Anda bisa membuat API di mana /users/[user_id]/emailsmengembalikan kumpulan alamat email untuk pengguna dengan id user_id. /users/[user_id]/emails/[email_id]mengembalikan email pengguna dengan user_id dan ['email_id']. Apa yang Anda gunakan sebagai pengenal terserah Anda, tetapi saya akan tetap menggunakan integer. Anda dapat menghapus email dari pengguna dengan mengirimkan DELETEpermintaan ke jalur yang mengidentifikasi email yang ingin Anda hapus. Jadi misalnya DELETEpada /users/[user_id]/emails/[email_id]akan menghapus email dengan email_id yang dimiliki oleh user dengan user_id. Kemungkinan besar hanya pengguna tersebut yang diizinkan melakukan operasi penghapusan ini. Pengguna lain akan mendapatkan respons 401.

Jika pengguna hanya dapat memiliki satu alamat email, Anda dapat tetap menggunakan /users/[user_id]/email Ini mengembalikan sumber daya tunggal. Pengguna dapat memperbarui alamat emailnya dengan PUTmemasukkan alamat email di url itu.

Melayu
sumber