Arama için RESTful URL tasarımı


427

Aramaları RESTful URL'ler olarak temsil etmek için makul bir yol arıyorum.

Kurulum: Arabaların Garajlarda olabileceği iki modelim var: Arabalar ve Garajlar. URL'lerim şöyle görünüyor:

/car/xxxx
  xxx == car id
  returns car with given id

/garage/yyy
  yyy = garage id
  returns garage with given id

Bir Araba kendi başına (dolayısıyla / araba) var olabilir veya bir garajda var olabilir. Belirli bir garajdaki tüm arabaları temsil etmenin doğru yolu nedir? Gibi bir şey:

/garage/yyy/cars     ?

Garaj yyy ve zzz araba birliği hakkında nasıl?

Belirli özelliklere sahip otomobiller için bir aramayı temsil etmenin doğru yolu nedir? De ki: 4 kapılı tüm mavi sedanları göster:

/car/search?color=blue&type=sedan&doors=4

ya da bunun yerine / arabalar mı olmalı?

"Arama" nın kullanımı orada uygunsuz görünüyor - daha iyi bir yol / terim nedir? Sadece olmalı:

/cars/?color=blue&type=sedan&doors=4

Arama parametreleri PATHINFO'nun veya QUERYSTRING'in bir parçası mı olmalı?

Kısacası, çapraz model REST url tasarımı ve arama için rehberlik arıyorum.

[Güncelleme] Justin'in cevabını beğendim, ancak çok alanlı arama durumunu kapsamıyor:

/cars/color:blue/type:sedan/doors:4

ya da böyle bir şey. Nasıl gidiyoruz

/cars/color/blue

çoklu alan durumu?


16
O karıştırma, İngilizce olarak daha iyi görünse de /carsve /carsemantik ve bu nedenle kötü bir fikir değildir. Bu kategorinin altında birden fazla öğe olduğunda daima çoğulu kullanın.
Zaz

4
Bunlar kötü cevaplar. Arama sorgu dizeleri kullanmalıdır. Sorgu dizeleri, doğru kullanıldığında (ör. Arama için)% 100 RESTful'dir.
pbreitenbach

Yanıtlar:


435

Arama için querystrings kullanın. Bu mükemmel RESTful:

/cars?color=blue&type=sedan&doors=4

Normal sorgu dizeleri için bir avantaj, standart ve yaygın olarak anlaşılmış olmaları ve form-get'den oluşturulabilmeleridir.


42
Doğru. Sorgu dizelerinin bütün amacı arama gibi şeyler yapmak içindir.
aehlke

22
Aslında bu doğrudur, RFC3986'ya göre yol ve sorgu dizesi kaynağı tanımlar. Dahası, uygun adlandırma basitçe olurdu /cars?color=whatever.
Lloeki

35
Karşılaştırıcı (>, <, <=,> =) istediğiniz durumlar ne olacak? / araba? değerlendirmesi <= 3?
Jesse

3
Sorgu dizesinin altına yerleştirilmiş kaynaklara erişmek istiyorsanız ne olur? Örneğin /cars?color=blue&type=sedan&doors=4/enginesişe yaramaz
Abe Voelker

9
mjs /cars?param=value, araba listesinde basit filtreleme içindir ve sonucun arama puanlaması, kategorizasyon, vb. içerebileceği /cars/search?param=valuebir arama ( kalıcılık olmadan) oluşturmak içindir /cars/search/mysearch. Şuna bakın: stackoverflow.com/a/18933902/1480391
Yves M.

121

RESTful güzel URL tasarımı bir yapıya dayalı bir kaynak göstererek hakkındadır (dizin benzeri yapıda, tarih: makaleler / 2005 / 5/13, nesne ve 's nitelikleri, ..), eğik çizgi /hiyerarşik yapısını gösterir kullanmak -idyerine.

Hiyerarşik yapı

Ben şahsen tercih ederim:

/garage-id/cars/car-id
/cars/car-id   #for cars not in garages

Bir kullanıcı /car-idparçayı kaldırırsa , carsönizlemeyi sezgisel olarak getirir . Kullanıcı ağacın neresinde olduğunu, neye baktığını tam olarak bilir. İlk bakıştan garajların ve arabaların birbiriyle ilişkili olduğunu biliyor. /car-idaynı zamanda bunun aksine birbirine ait olduğunu gösterir /car/id.

Aranıyor

Arama sorgusu olduğu gibi , sadece sizin tercihiniz var, nelerin dikkate alınması gerektiği. Komik kısım aramalara katılırken gelir (aşağıya bakın).

/cars?color=blue;type=sedan   #most prefered by me
/cars;color-blue+doors-4+type-sedan   #looks good when using car-id
/cars?color=blue&doors=4&type=sedan   #I don't recommend using &*

Ya da temelde yukarıda açıklandığı gibi eğik çizgi olmayan herhangi bir şey.
Formül:, /cars[?;]color[=-:]blue[,;+&]* &işareti ilk bakışta metinden tanınamadığı için kullanmam .

** URI'de JSON nesnesini geçirmenin RESTful olduğunu biliyor muydunuz? **

Seçenek listeleri

/cars?color=black,blue,red;doors=3,5;type=sedan   #most prefered by me
/cars?color:black:blue:red;doors:3:5;type:sedan
/cars?color(black,blue,red);doors(3,5);type(sedan)   #does not look bad at all
/cars?color:(black,blue,red);doors:(3,5);type:sedan   #little difference

olası özellikler?

Sıralı arama dizeleri (!) Siyah ve kırmızı değil
, herhangi bir aracı aramak için :
?color=!black,!red
color:(!black,!red)

Katılım aramalar
Arama kırmızı veya mavi ya da siyah ile araba 3 garajlar id kapı 1..20 veya 101..103 veya 999 ama değil 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
Daha sonra daha karmaşık arama sorgular oluşturabilirsiniz. ( Alt dizeleri eşleştirme fikri için CSS3 öznitelik eşleşmesine bakın. Örn. "Bar" içeren kullanıcıları aramak user*=bar.)

Sonuç

Sadece akılda tutmak, sonuçta gibi ancak sen yapabilirsin çünkü Neyse, bu, sizin için en önemli parçası olabilir RESTful URI kolayca örneğin dizin benzeri anlaşılmış olan bir yapıyı temsil /directory/file, /collection/node/itemtarih /articles/{year}/{month}/{day}.. Ve atladığınızda Son segmentlerden herhangi birinde, ne elde ettiğinizi hemen bilirsiniz.

Yani, tüm bu karakterlerin kodlanmamış olmasına izin verilir :

  • rezerve edilmemiş : a-zA-Z0-9_.-~
    Tipik olarak hem kodlanmış hem de kodlanmamıştır, her iki kullanım da eşdeğerdir.
  • özel karakterler: $-_.+!*'(),
  • ayrılmış: ;/?:@=&
    Temsil ettikleri amaç için kodlanmamış olarak kullanılabilir, aksi takdirde kodlanması gerekir.
  • güvensiz: <>"#%{}|\^~[]`
    Neden güvensiz ve neden kodlanmalı: RFC 1738 bkz. 2.2

    Ayrıca daha fazla karakter sınıfı için RFC 1738 # sayfa-20'ye bakın.

RFC 3986 2.2 bkz
daha önce söylediklerini rağmen, burada bazı yani delimeters ortak bir ayrımdır "dir" diğerlerinden daha önemli.

  • genel sınırlayıcılar: :/?#[]@
  • alt delimeters: !$&'()*+,;=

Daha fazla okuma:
Hiyerarşi: bkz. 2.3 , bkz. 1.2.3
url yolu parametresi sözdizimi
CSS3 özniteliği eşleşen
IBM: RESTful Web hizmetleri - Temel bilgiler
Not: RFC 1738, RFC 3986 tarafından güncellendi


3
Sorgu dizesinde JSON kullanmayı düşünmediğime inanmıyorum. Karşılaştığım bir sorunun cevabı - kullanmadan karmaşık arama yapısı POST. Ayrıca, cevabınızda verdiğiniz diğer fikirler de son derece takdir edilebilir. Çok teşekkürler!
gustavohenke

4
@ Qwerty: harika gönderi! Merak ediyordum: ;aksine kullanmanın tek nedeni &okunabilirlik mi? Çünkü eğer öyleyse, &daha yaygın sınırlayıcı olduğu için aslında tercih edeceğimi düşünüyorum ... değil mi? :) Teşekkürler!
Flo

3
@ Evet Evet tam olarak :), ancak &bir sınırlayıcı olarak sadece geliştiriciler tarafından bilindiğini unutmayın . Ebeveynler, büyükanne ve büyükbabalar ve eğitimsiz nüfus, ortak yazılı metinde kullanılan sınırlayıcıları kabul eder.
Qwerty

17
Sorgu dizeleri iyi anlaşıldığında ve standart olduğunda neden standart olmayan bir düzen oluşturmalısınız?
pbreitenbach

1
@Qwerty hiçbir şey / arama? Arabalar = kırmızı, mavi, yeşil ve garajlar = 1,2,3 durduran veya <multiselect> formu kullanırsanız: / search? Cars = kırmızı & cars = mavi & garajlar = 1 & garajlar = 2
pbreitenbach

36

Parametrelerin yola sahip olmasının bazı avantajları olmasına rağmen, IMO, bazı ağır basan faktörler vardır.

  • Bir URL'de arama sorgusu için gereken tüm karakterlere izin verilmez. Çoğu noktalama işareti ve Unicode karakterinin bir sorgu dizesi parametresi olarak URL ile kodlanması gerekir. Aynı problemle güreşiyorum. URL'de XPath kullanmak istiyorum, ancak tüm XPath sözdizimi bir URI yolu ile uyumlu değil. Bu yüzden basit yollar için, sürücü kapısı XML belgesinde /cars/doors/driver/lock/combination' combination' öğesini bulmak uygun olacaktır . Ama /car/doors[id='driver' and lock/combination='1234']o kadar kolay değil.

  • Bir kaynağı özniteliklerinden birine göre filtreleme ve bir kaynağı belirtme arasında bir fark vardır.

    Örneğin,

    /cars/colors tüm arabalar için tüm renklerin bir listesini döndürür (döndürülen kaynak bir renk nesneleri koleksiyonudur)

    /cars/colors/red,blue,green araba koleksiyonu değil, kırmızı, mavi veya yeşil renkli nesnelerin bir listesini döndürür.

    Arabaları iade etmek için yol

    /cars?color=red,blue,green veya /cars/search?color=red,blue,green

  • Ad / değer çiftleri, ad / değer çiftleri olmayan yolun geri kalanından izole edilmediğinden yoldaki parametrelerin okunması daha zordur.

Son bir yorum. Tekil ve çoğul arasındaki yolu değiştirmekten kaçındığı /garages/yyy/carsiçin (her zaman çoğul) tercih ederim ( /garage/yyy/carsbelki de orijinal cevapta bir yazım hatasıydı). 'S' ibaresi eklenmiş kelimeler için bu değişiklik o kadar da kötü değildir, ama yerine /person/yyy/friendsgeçmek /people/yyyzahmetli görünmektedir.


2
evet, katılıyorum ... yanı sıra urls yol yapısı varlıklar arasındaki doğal ilişkileri yansıtmalıdır, benim kaynaklarımın bir tür haritası, bir garaj çok araba var, bir araba bir garaja aittir ve böylece ... ve izin filtre parametreleri, neden bahsettiğimiz budur, sorgu dizgisine que ... ne düşünüyorsun?
açılır

31

Peter'ın cevabını genişletmek için - Arama'yı birinci sınıf bir kaynak yapabilirsiniz:

POST    /searches          # create a new search
GET     /searches          # list all searches (admin)
GET     /searches/{id}     # show the results of a previously-run search
DELETE  /searches/{id}     # delete a search (admin)

Arama kaynağında renk, marka oluşturma modeli, garaj durumu vb. Alanları bulunur ve XML, JSON veya başka bir biçimde belirtilebilir. Araba ve Garaj kaynağı gibi, kimlik doğrulamasına dayalı olarak Aramalara erişimi kısıtlayabilirsiniz. Aynı Aramaları sık sık çalıştıran kullanıcılar, profillerinde saklanabilmeleri için yeniden oluşturulmalarına gerek kalmaz. URL'ler, çoğu durumda e-posta yoluyla kolayca alınıp satılabilecek kadar kısa olacaktır. Saklanan bu Aramalar özel RSS akışlarının temelini oluşturabilir vb.

Aramaları kaynak olarak düşündüğünüzde pek çok olasılık vardır.

Fikir bu Railscast'de daha ayrıntılı olarak açıklanmaktadır .


6
bu yaklaşım huzursuz bir protokolle çalışma fikrine aykırı değil mi? Yani, bir db aramaya devam etmek durumsal bir bağlantı olması bir tür ... değil mi?
48'de açılır

5
Daha çok durum bilgisi olan bir hizmete sahip olmak gibidir. Ayrıca her yeni Araba veya Garaj eklediğimizde hizmetin durumunu değiştiriyoruz. Arama, tüm HTTP fiilleriyle kullanılabilecek başka bir kaynaktır.
Rich Apodaca

2
Yukarıdakiler bir URI kuralını nasıl tanımlar?
Rich Apodaca

3
REST'in güzel URI'ler veya URI yuvalama vb. İle ilgisi yoktur. URI'ları API'nizin bir parçası olarak tanımlarsanız, REST değildir.
aehlke

2
Bunu daha önce tartışmıştım. Bu durumun bir yolu yok, ama korkunç bir şey. Aramanın 'sil' işlemi tam olarak net değil, burada bu arama varlığını sildiğini söylüyorsunuz, ancak bu aramada bulduğum sonuçları silmek için kullanmak istiyorum. Lütfen kaynak olarak 'arama' eklemeyin.
thecoshman

12

Bazı uygulamalarda, belirli bir aramayı kendi başına bir kaynak olarak düşünmek mantıklı olsa da, Justin'in yanıtı muhtemelen gitmenin yoludur: kaydedilmiş aramaları desteklemek istiyorsanız:

/search/{searchQuery}

veya

/search/{savedSearchName}

11
Hayır. bir eylemin kaynak olması asla mantıklı değildir.
thecoshman

3
@thecoshman yukarıdaki yorumda belirtildiği gibi, arama da bir isimdir.
andho

6

Aramaları uygulamak için iki yaklaşım kullanıyorum.

1) İlişkili öğeleri sorgulamak ve gezinmek için en basit durum.

    /cars?q.garage.id.eq=1

Bu, garaj kimliği 1'e eşit olan arabaları sorgula anlamına gelir.

Daha karmaşık aramalar oluşturmak da mümkündür:

    /cars?q.garage.street.eq=FirstStreet&q.color.ne=red&offset=300&max=100

FirstStreet'teki tüm garajlarda kırmızı olmayan otomobiller (3. sayfa, sayfa başına 100 eleman).

2) Karmaşık sorgular, oluşturulan ve geri kazanılabilen düzenli kaynaklar olarak kabul edilir.

    POST /searches  => Create
    GET  /searches/1  => Recover search
    GET  /searches/1?offset=300&max=100  => pagination in search

Arama oluşturmak için POST gövdesi aşağıdaki gibidir:

    {  
       "$class":"test.Car",
       "$q":{
          "$eq" : { "color" : "red" },
          "garage" : {
             "$ne" : { "street" : "FirstStreet" }
          }
       }
    }

Grails (DSL ölçütleri) tabanlıdır: http://grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html


5

Bu REST değil. API'nizdeki kaynaklar için URI tanımlayamazsınız. Kaynakta gezinme köprü metnine dayalı olmalıdır. Güzel URI'ler ve ağır miktarda kuplaj istiyorsanız iyi olur, ancak sadece REST olarak adlandırmayın, çünkü RESTful mimarisinin kısıtlamalarını doğrudan ihlal eder.

REST'in mucidi tarafından bu makaleye bakın .


28
REST olmadığı doğru, RESTful sistemi için URL tasarımı. Bununla birlikte, RESTful mimarisini ihlal ettiğini söylemede de yanılıyorsunuz. REST'in hipermetin kısıtlaması, RESTful sistemi için iyi URL tasarımına diktir; Birkaç yıl önce REST listesinde Roy T. Fielding ile bu kadar açık bir şekilde ifade ettiği yere katıldığım bir tartışma olduğunu hatırlıyorum. Başka bir deyişle, köprü metni ve URL tasarımına sahip olmak mümkündür. RESTful sistemleri için URL tasarımı programlamadaki girinti gibidir; gerekli değil ama çok iyi bir fikir (Python, vb. yok
sayılıyor

2
Üzgünüm, haklısın. OP'den müşterileri URL'lerin nasıl oluşturulacağı konusunda bilgilendirecek bir izlenim edindim - URL'yi "düzenleri" API'sının bir parçası haline getirecekti. Bu REST'in ihlali anlamına gelir.
aehlke

@aehlke, cevabınızı yorumunuza uyacak şekilde güncellemelisiniz.
James McMahon

1
Seviye 2 Richardson olgunluk modeli ile uyumludur. 3. seviyeye atıfta bulunuyorsunuz. Sadece REST'i aşamalı olarak kabul edilebilir bir şey olarak kabul edin.
Jules Randolph

1
@Jules Randolph - özür dilerim, cevabım Richardson olgunluk modelinin ilk ortaya çıkmasından aylar sonra ve Martin Fowler ve diğer yazarlar popüler hale gelmeden önce yazılmıştı :) Gerçekten de, bunu takip etmek öğretici bir model. Cevabı düzenlemekten çekinmeyin.
aehlke

1

Justin'in yanıtını beğenmeme rağmen, bir aramadan ziyade bir filtreyi daha doğru bir şekilde temsil ettiğini hissediyorum. Kamera ile başlayan isimleri olan arabalar hakkında bilmek istersem ne olur?

Gördüğüm gibi, onu belirli kaynakları kullanma biçiminize göre inşa edebilirsiniz:
/ cars / cam *

Ya da filtreye ekleyebilirsiniz:
/ cars / doors / 4 / name / cam * / colors / red, mavi, yeşil

Şahsen, ikincisini tercih ederim, ancak hiçbir şekilde REST konusunda bir uzman değilim (sadece 2 hafta kadar önce duymuştum ...)


/cars?name=cam*
Şunun

1

RESTful, URL'lerde / cars / search'de fiil kullanılmasını tavsiye etmemektedir. API'lerinizi filtrelemenin / aramanın / sayfalandırmanın doğru yolu Sorgu Parametreleri'dir. Bununla birlikte, normu kırmanız gereken durumlar olabilir. Örneğin, birden fazla kaynak arasında arama yapıyorsanız, / search? Q = query gibi bir şey kullanmanız gerekir.

Sen geçebilir http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/ RESTful API'lerini tasarlamak için en iyi uygulamaları anlamak


1
Arama bir isim de 😀
jith912

1

Ayrıca ben de öneririm:

/cars/search/all{?color,model,year}
/cars/search/by-parameters{?color,model,year}
/cars/search/by-vendor{?vendor}

Burada, Searchalt kaynak kaynağı olarak kabul edilir Cars.


1

Burada davanız için birçok iyi seçenek var. Yine de POST gövdesini kullanmayı düşünmelisiniz.

Sorgu dizesi örneğiniz için mükemmeldir, ancak daha karmaşık bir öğeniz varsa (örneğin, keyfi olarak uzun bir öğe listesi veya boole koşulu), postayı istemcinin POST üzerinden gönderdiği bir belge olarak tanımlamak isteyebilirsiniz.

Bu, aramanın daha esnek bir açıklamasına izin verir ve Sunucu URL uzunluk sınırını önler.


-4

Benim tavsiyem şu olurdu:

/garages
  Returns list of garages (think JSON array here)
/garages/yyy
  Returns specific garage
/garage/yyy/cars
  Returns list of cars in garage
/garages/cars
  Returns list of all cars in all garages (may not be practical of course)
/cars
  Returns list of all cars
/cars/xxx
  Returns specific car
/cars/colors
  Returns lists of all posible colors for cars
/cars/colors/red,blue,green
  Returns list of cars of the specific colors (yes commas are allowed :) )

Düzenle:

/cars/colors/red,blue,green/doors/2
  Returns list of all red,blue, and green cars with 2 doors.
/cars/type/hatchback,coupe/colors/red,blue,green/
  Same idea as the above but a lil more intuitive.
/cars/colors/red,blue,green/doors/two-door,four-door
  All cars that are red, blue, green and have either two or four doors.

Umarım bu size fikir verir. Temel olarak Rest API'nız kolayca bulunabilir ve verilerinize göz atmanıza olanak tanır. URL'leri kullanmanın ve sorgu dizelerini kullanmanın bir diğer avantajı, HTTP trafiği için web sunucusunda bulunan yerel önbellekleme mekanizmalarından yararlanabilmenizdir.

İşte REST'teki sorgu dizelerinin kötülüklerini açıklayan bir sayfaya bağlantı: http://web.archive.org/web/20070815111413/http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful

Google'ın önbelleğini kullandım, çünkü normal sayfa benim için çalışmıyor: http://rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful


1
Detaylı cevap için teşekkürler. Sonuncusu, hem renk hem de kapı sayısına göre aramak istersem ne olur? / cars / colors / kırmızı, mavi, yeşil / kapılar / 4 Bu doğru görünmüyor.
Parand

2
URL'deki virgüller bana doğru gelmiyor, ama yine de geçerli. Bence bu sadece bir paradigma değişimi.
Justin Bozonier

21
Bu öneriyi sevmiyorum. Nasıl arasındaki farkı bilemez /cars/colors/red,blue,greenve /cars/colors/green,blue,red? URI'nin yol öğesi hiyerarşik olmalıdır ve burada böyle olduğunu gerçekten görmüyorum. Bu sorgu-string en uygun seçim olduğu bir durum olduğunu düşünüyorum.
troelskn

62
Bu kötü bir cevap. Aslında, aramayı uygulamanın doğru yolu sorgu dizeleriyle ilgilidir. Sorgu dizeleri düzgün kullanıldığında en ufak bir kötülük değildir. Atıfta bulunulan makale aramaya değinmiyor. Sağlanan örnekler açıkça işkence gördü ve daha fazla parametreye dayanamadı.
pbreitenbach

4
querystrings öncelikle bir kaynağı sorgulama problemini çözmek için birden fazla parametreyle bile yapılmıştır. "RESTful" API'sini etkinleştirmek için URI'yi saptırmak tehlikeli ve kısa görüşlü görünüyor - özellikle URI'deki çeşitli parametre permütasyonlarını işlemek için kendi karmaşık eşlemelerinizi yazmak zorunda kalacağınızdan. Daha da iyisi, URI'larınızda zaten mevcut olan noktalı virgül kavramını kullanın: doriantaylor.com/policy/http-url-path-parameter-syntax
Anatoly G
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.