Karmaşık bir RESTful arama yöntemi yapmanın uygun bir yolu nedir?


44

REST ilkelerini izleyerek, API’m için bazı kriterler kullanarak arama yapan ve sonuçları müşteriye döndüren bir GET yöntemi oluşturmak isterdim. Sorun şu ki, kriterler 14 parametreye sahip olabilir, bunlardan biri karmaşık nesnelerin listesi, yani ...

  • Bu karmaşık nesneleri kodlama / kod çözme işleminin url parametrelerine yapılıp yapılamayacağını bile bilmiyorum.

  • URL'nin ne kadar süre alabileceğini hesaplayamadım, ancak yeterince büyük olacağından ve belki de URL uzunluk sınırına ulaşabileceğinden emin miyim?

Ayrıca, arama sonuçları "gerçek zamanlı" olarak göstermelidir, yani kullanıcı arama formundan bir şey değiştirdiğinde, herhangi bir "arama" düğmesine basmadan yeni sonuçları görebilmesi gerekir.

Bana bu noktaları açıklığa kavuşturabilir misiniz ve pek çok parametreli dinlendirici bir arama yöntemi oluşturmak için tavsiyeniz ne olurdu?


3
Bir kenara (yazma sırasındaki iki cevaptan hiçbirinin gerçek zamanlı kısımdan bahsetmediğine dikkat çekiyorum), gerçek zamanlı aramalar tipik olarak sadece güncellenmiş talebi tekrar tekrar göndermelidir. Örneğin, sen yazarak ederken, sizin gibi şeyler için istek gönderebilir ediyorum search?q=t, search?q=te, search?q=test, vb. Sunucunuzun zarar görmemesi için sorgunun ne sıklıkla gönderileceğini sınırlamayı düşünün. Alternatif olarak birçok bilgiyi geri gönderebilirsiniz ve müşteri tarafında filtreleme yapabilirsiniz. Kullanıcı işleri büyük ölçüde daraltabilecek geniş kategorilere girerse işe yarar.
Kat

2
Çözüm ne olursa olsun, verileri teknolojiden bağımsız bir biçimde değiştirdiğinizden emin olun. Bu yüzden dahili bir temsil kullanmayın, aksi takdirde API'nize istemciler yazmak daha zor olacaktır.
Kwebble,

Gereksinimlerinize bağlı olarak, bu kütüphane işi yapabilir: github.com/jirutka/rsql-parser . JPA kullanıyorsanız, bir JPA uzantısına sahiptir veya arama motorunuzun API'sine eşlemek için kendi Ziyaretçinizi yazabilirsiniz. Ve kendi operatörünüzü ekleyebilirsiniz.
Walfrat

Yanıtlar:


54

Cevabımı okumadan önce @Neil ile hemfikir olduğumu söylemek isterim. Savaşlarımızı seçmeliyiz. Genellikle elimizden gelenin en iyisini yapmak istiyoruz, ancak bazen tartışma için çok az yer var ve isteğimize karşı kararlar almak zorundayız.

Neyse, Neil'in cevabında bir şeyi daha özlüyorum. Belgeler . Yalnızca geliştiricilerin POST isteklerinin /searchgüvenli olduğunu bilmelerini sağlamak .

Bahsedilen.

1. GET'e bir şans verin

GETİlk önce seçeneği düşünün . Bu soru URL’sinin maksimum uzunluğunu kontrol edin . En uzun sorgu dizenizin 2000 karakterden uzun olup olmadığını değerlendirin. Olmazsa ve olmasını beklemiyorsanız devam edin GET. Çirkin görünebilir, ama en azından URL'yi işaretleyebilirsiniz ve elbette, yöntemin anlambiliminden (idempotence, güvenli ve önbellekleme) elde edilen tüm avantajları vardır.

1.1 Sorgu dizesini kodlamayı deneyin

Örneğin, 64 tabanında . Javascript bile 64 taban kodlamasını destekler .

Bu nasıl çalışır:

  1. JSON'u tüm filtrelerle oluşturun ve normalleştirin.
  2. Dizeye ayrıştır
  3. Kodla
  4. Kodlanmış JSON'u istek param ( /search?q=SGVsbG8gV29ybGQh....) olarak gönderin .
  5. Sunucu tarafında, q paramunun kodunu çözün .
  6. JSON dizesini seri hale getirin

Önceden, mümkün olan en uzun JSON dizesini yapın, kodlayın ve uzunluğu alın. Kodlanmış dizenin URL'ye uyup uymadığını değerlendirin. Aşağıdaki snippet'i Fiddle.js üzerinde test etmeniz için uyguladım . (Umarım hala çalışır) 1

Base 64 kodları deterministik ve geri dönüşümlüdür, bu nedenle çarpışma olasılığı yoktur.

Kodlanmış sorgularla, aramaları DB'ye kaydedebilir, URL'yi yer imlerine ekleyebilir, bağlantıları paylaşabiliriz, vb. Ve tabii ki, dizeden kaçmak / unescape yapmak zorunda değiliz.

1.2 Diğer adlarla deneyin

REST API'lerinin nasıl tasarlandığına dair bu blogu okuduğumda bir alternatif daha hatırladım. Yaygın sorgular için takma adlar .

Bunları sonraki nedenlerden dolayı ilginç buluyorum

  • Sorgu dizesi uzunluğunu kısaltın. API'yi daha temiz ve kullanıcı dostu yapar

    GET / biletler /? Durum = kapalı & kapalıAt = xxx - GET / biletler / yeni kapanan /

  • Daha fazla takma ad veya daha fazla istek parametresiyle birlikte kullanılabilir.

    GET / bilet /? Durum = kapalı & kapalıAt = xxx & içinde = 30dk vs GET / biletler / yeni kapatılan /?

  • Takma adları kodlanmış sorgu dizeleriyle birleştirebiliriz

    GET / bilet /? Durum = kapalı & kapalıAt = xxx & içinde = 30dk vs GET / biletler / yeni kapatılan /? Q = SGVsbG8g ...


1: JSON kullandım, ancak sunucu tarafında seriyi kaldırır çözmez diğer biçimleri de kullanabiliriz.


2
Bu hem pratik hem de doğru. Programlama dillerinin çoğunun bir karma diziyi sorgu dizgisine dönüştürmeyi önemsiz kıldığına dikkat etmek önemlidir; bu nedenle bir GET eylemiyle başlamak çok kolaydır.
Aluan Haddad,

1
Ben bahar stackoverflow.com/questions/16942193/… İlk denemede çalıştığına inanamıyorum: D. URL uzunluğu hakkında, yine de özellikleri yinelememiz gerekmesine rağmen 1k'den az.
anat0lius

Sonra GET ile gidin. Basitlik için. Spring MVC ile GET ile aynı haritalamayı elde edebilirsiniz. ;-) Spring'in WebArgumentResolver için bak
LAIV

Base64, yük kapasitesini 4/3 oranında şişiriyor. URL kodlaması özel karakterler için 3/1 yapabilirken, çoğunlukla güvenli karakterleri içeren sorgular aynı boyutta kalır. Base64'ü kullanmak için başka bir neden var mı?
villasv

Pek sayılmaz. Sadece kaçış URL'lerini beğenmedim. Yükün fazlalığı, buradaki harabedir. Yine de istek başına GET'in maksimum boyutuna sığması gerekir. Bu yüzden pasajı yaptım. Kullanıcı denemek için. Cevabı yazdığımda, web anlambilimini uygulama detaylarına göre önceden belirledim. Cevabın asıl amacı "GET ile denemeye devam etmektir". Yolunu bul ya da seninle paylaştığım bunlardan herhangi birini kullan.
Laiv

13

Sahip olduğun tek şey bir çekiçse, her şey bir çiviye benziyor. Buradaki problem, bir arama sayfasını RESTful'a çevirmeye çalıştığınız gibi görünüyor ve bu RESTful tasarımının çözmesi için ortak bir kalıp gibi görünmüyor.

İstediğiniz bilgiyi arka uçtan almak için, kullanıcı tarafından sağlanan parametreleri içeren bir POST talebiyle gitmeniz yeterli. Bir arama yapmaktan başka bir şey yapmanıza gerek olmadığını sanıyorum, bu yüzden bu sayfayı eklemeniz gerekmiyor. URL’nizin sonuna bir / arama ekleyin, böylece / kullanıcılar sayfanızla RESTful olabilecek çakışma riskiyle karşılaşmazsınız .


2
@LiLou_: Bu gereksinim için sadece iki gerçekçi olasılık var: 1. Tüm verileri ön ucuna okuyup filtrelemeyi yap. İstenilen miktarda hafıza için bu yasaklayıcı olabilir. 2. Arama kriterlerindeki her değişiklik için sunucuya yeni bir istek yapın. Bunun bir POST veya GET isteği olup olmadığı önemli değildir, ancak söz konusu ağ gecikmesi, kullanıcının "gerçek zamanlı" güncellemeler algısı için rahatsız edici olabilir.
Bart van Ingen Schenau

2
Kabul etmemeyi kabul ediyorum, POST anlamsal olarak başka bir şey ifade ediyor. GET ile gidip sorgu parametresindeki tüm filtre verilerini iletmeyi öneririm. Eğer çok fazla parametre varsa o zaman uygulama düzeyinde bir hata var.
CodeYogi

2
@CodeYogi bazen müşteri size karışıklık için yer vermez. Her biri 40-50 sütunlu Excel benzeri görünüm sayfalarını kendi filtreleriyle uyguladım. Ve elbette sıralanabilir. Her neyse, GET ile hala mümkün ama çok moda görünmeyebilir
Laiv

1
@Laiv'in bu durumda ciddi bir tartışmaya ihtiyacı var çünkü POST sunucu durumundaki değişikliği ifade ediyor. Bunun gibi kullanım durumları istisnai değildir, bu yüzden kesmeksizin ilgilenilmelidir.
CodeYogi

2
Bu durumlarda, belgeler şarttır . Müşterilerin uygulamalarının kullanılabilirliği konusunda ciddi bir tartışma yaptım. Daha sonra haklı olduğum kanıtlandı çünkü son kullanıcı benimle aynı fikirdeydi. Ancak, bazen savaşlarını seçmelisin.
Laiv

0

Tamamen API modelinizin ne olduğuna bağlıdır: Yok olarak veya fiil olarak.

API hiçbiri değilse, aşağıdaki gibi nesnelerin listesini almak isteyebilirsiniz:

GET: /api/v1/objects

Bu durumda, verileri istek parametreleri olarak göndermelisiniz. Bu nedenle parametrelerinizi düz bir anahtar-değer listesi olarak tanımlamanız gerekir:

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

Bazı platformlar paramları bir nesneye dönüştürebileceğiniz özel parametre çözümleyiciyi (örneğin Spring MVC) destekler.

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.