Uzun bir sorgu parametreleri listesiyle RESTful sorgu API'sini tasarlayın [kapalı]


153

Birkaç filtreler dayalı nesneleri kümesi döndüren bir RESTful sorgu API tasarlamak gerekiyor. Bunun için genel HTTP yöntemi GET'tir. Tek sorun, en az bir düzine filtreye sahip olabilir ve hepsini sorgu parametreleri olarak geçirirsek, URL oldukça uzayabilir (bazı güvenlik duvarları tarafından engellenecek kadar uzun).

Parametre sayısını azaltmak bir seçenek değildir.

Düşünebileceğim bir alternatif, URI üzerindeki POST yöntemini kullanmak ve filtreleri POST gövdesinin bir parçası olarak göndermek. Bu RESTfull olmak (veri sorgulamak için bir POST çağrısı yapma) karşı.

Daha iyi bir tasarım önerisi olan var mı?


2
Kısa (1 karakter, vb.) Parametre adları kullanılsın mı?
Madbreaks

2
Gerçekten RESTful olmayabilir, ancak GET'ler ve POST'lar söz konusu olduğunda pratik olmanız gerektiğini düşünüyorum. Gönderecek çok değişkeniniz varsa ve bunları azaltamazsanız, POST EDERİM. URL'yi fazla doldurmaktan hoşlanmıyorum, ama bu sadece benim.
Doug Dawson

Teşekkürler. Bu soru kapalı olmasına rağmen, tam olarak bir cevaba ihtiyaç duyduğum soru. Sorduğun için minnettarım.
Casey Crookston

Yanıtlar:


142

Bir REST API'sinde, tümünün sizin bakış açınızla ilgili bir soru olduğunu unutmayın.

Bir REST API'sindeki iki temel kavram, uç noktalar ve kaynaklardır (varlıklar). Gevşek bir şekilde, bir uç nokta ya kaynakları GET aracılığıyla döndürür ya da POST ve PUT ve benzeri aracılığıyla kaynakları kabul eder (ya da yukarıdakilerin bir kombinasyonu).

POST ile, gönderdiğiniz verilerin, büyük olasılıkla POST'lu URL altında "canlı" olmayacak yeni bir kaynak ve bununla ilişkili bitiş noktalarının oluşturulmasına neden olabileceği veya sonuçlanmayabileceği kabul edilir. Başka bir deyişle, POST yaptığınızda, işlem yapmak için bir yere veri gönderirsiniz. POST bitiş noktası, kaynağın normal olarak bulunabileceği yer değildir.

RFC 2616'dan alıntı yapma (alakasız parçalar atlanmış ve ilgili parçalar vurgulanmış olarak):

9.5 SONRASI

POST yöntemi, kaynak sunucunun, istekte yer alan varlığı İstek Satırında Request-URI tarafından tanımlanan kaynağın yeni bir alt öğesi olarak kabul etmesini istemek için kullanılır. POST, aşağıdaki işlevleri kapsayan tek tip bir yönteme izin verecek şekilde tasarlanmıştır:

  • ...
  • Veri işleme sürecine form gönderme sonucu gibi bir veri bloğunun sağlanması;
  • ...

...

POST yöntemi tarafından gerçekleştirilen eylem, bir URI tarafından tanımlanabilecek bir kaynakla sonuçlanmayabilir . Bu durumda, yanıtın sonucu tanımlayan bir varlık içerip içermediğine bağlı olarak 200 (Tamam) veya 204 (İçerik Yok) uygun yanıt durumudur .

Kaynak sunucuda bir kaynak oluşturulduysa, yanıt 201 olmalıdır (Oluşturuldu) ...

Sorun alanı ne olursa olsun, bir kullanıcı, bir mesaj, bir kitap olsun, 'şeyleri' veya 'verileri' temsil eden uç noktalara ve kaynaklara alıştık. Ancak, bir bitiş noktası farklı bir kaynağı da ortaya çıkarabilir - örneğin arama sonuçları.

Aşağıdaki örneği düşünün:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

Bu tipik bir REST CRUD. Ancak eklersek:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

Bu son nokta hakkında RESTful olmayan bir şey yok. Verileri (varlık) istek kuruluşu biçiminde kabul eder. Bu veriler Arama Kriterleri'dir - diğerlerine benzeyen bir DTO. Bu uç nokta, isteğe göre bir kaynak (varlık) üretir: Arama Sonuçları . Arama sonuçları kaynağı, istemciye hemen, yeniden yönlendirmeden ve başka bir kurallı URL'den etkilenmeden sunulan geçici bir kaynaktır.

Varlıklar kitap değildir, ancak istek varlığı kitap arama ölçütleri ve yanıt veren varlık kitap arama sonuçlarıdır.


DTO için bazı isimlendirme kuralları önerebilir misiniz?
Kwadz

Şahsen BooksSearchCriteriaDTOve ile giderdim BooksSearchResultsDTO.
Amir Abiri

Bu POST / kitaplar / arama durumu için en iyi HTTP yanıt kodu ne olabilir? 201 hala geçerli mi?
L. Holanda

9
201 tam tersidir - bir kaynağın yaratıldığı anlamına gelir. Bir yerde kendine özgü URI'sı olması beklenen bir kaynak. 201, POSTCRUD'nin C kısmı için kullanıldığında uygundur . Boş arama sonuçları için isteğe bağlı olarak belki 204 ile düz eski 200 ile giderdim.
Amir Abiri

@AmirAbiri çok teşekkür ederim.
mohamed-mhiri

84

Birçok kişi, çok uzun veya çok karmaşık bir sorgu dizesine sahip bir GET'in (örneğin, sorgu dizeleri yuvalanmış verileri kolayca işleyemediği) bunun yerine, gövdede temsil edilen karmaşık / uzun verilerin temsil edildiği bir POST olarak gönderilebileceği uygulamasını kabul etmiştir. istek.

HTTP spesifikasyonunda POST spesifikasyonuna bakın. İnanılmaz derecede geniş. (REST'teki bir boşluktan bir zırhlıya yelken açmak istiyorsanız ... POST kullanın.)

GET semantiğinin bazı avantajlarını kaybedersiniz ... otomatik yeniden deneme gibi GET iktidarsızdır, ancak bununla yaşayabilirseniz, POST ile gerçekten uzun veya karmaşık sorguları işlemeyi kabul etmek daha kolay olabilir.

(lol uzun anlatılanlar ... Geçenlerde HTTP Spec, GET tarafından keşfetti olabilir . Bir belge gövdesini içeren başka sözcüklerle diyor bir bölüm var "Herhangi bir istek bu bölümde listelenen dışındaki bir belge vücuda sahip olabilir" ... HTTP yazarlarının bu konu hakkında konuştuğu bir konu aradım ve yönlendirdim, böylece yönlendiriciler ve benzeri farklı iletiler arasında ayrım yapmak zorunda kalmayacaksınız. birçok altyapı parçasının bir GET'in gövdesini düşürmesini sağlayın, böylece POST gibi vücutta temsil edilen filtrelerle GET alabilirsiniz, ancak zarları yuvarlayabilirsiniz.)


11
Ayrıca , gövdeli HTTP GET hakkında daha fazla tartışma için bu soruya bakın .
RickyA

6

Özetle: Bir POST yapın ancak X-HTTP-Method-Override üstbilgisini kullanarak HTTP yöntemini geçersiz kılın .

Gerçek istek

POST / kitaplar

Varlık kuruluşu

{"title": "Ipsum", "yıl": 2017}

Başlıkları

X-HTTP-Yöntem-Geçersiz Kılma: GET

Sunucu tarafında, X-HTTP-Method-Override üstbilgisinin mevcut olup olmadığını kontrol edin, ardından değerini arka uçtaki son uç noktaya giden yolu oluşturma yöntemi olarak alın. Ayrıca varlık gövdesini sorgu dizesi olarak alın. Bir arka uç bakış açısından, istek sadece basit bir GET oldu.

Bu şekilde tasarımı REST ilkeleriyle uyumlu tutarsınız.

Düzenleme: Bu çözümün aslında bazı tarayıcılarda ve sunucularda PATCH fiil sorununu çözmek için tasarlandığını biliyorum ama aynı zamanda soruda açıklanan sorun olan çok uzun bir URL durumunda GET fiiliyle de çalışır.


2
IETF X ön ekli HTTP üstbilgilerini kullanımdan kaldırdı
jannis


@jannis Bağladığınız RFC 1.4'te kalır. mevcut X-kaldırmayla ilgili herhangi bir öneri getirmez ve 1.5. mevcut özellikleri geçersiz kılmaz. ... X-IMO burada kalacak mı?
Jan Molnar

-3

Java ve JAX-RS'de geliştiriyorsanız @GET ile @QueryParam kullanmanızı öneririz

Bir listeden geçmem gerektiğinde de aynı soruya sahiptim.

Örneğe bakın:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

URI Kalıbı: “poc / test? Code = 1 & code = 2 & code = 3

@QueryParam , “orderBy = age & orderBy = name” sorgu parametresini otomatik olarak java.util.List dosyasına dönüştürür.


Örneğinizi açıklarsanız daha iyi olur. Hangi programlama dilinde yazılıyor?
Aleks Andreev

Merhaba @AleksAndreev. Fikrin için teşekkür ederim. Daha iyi oldu mu? tks
acacio.martins

Bu soru, uygulama ile değil RESTful hizmetinin tasarımı ile ilgilidir. Bu cevap soruyu cevaplamıyor.
Heretic Maymun

@ user1331413 IMHO evet, şimdi daha iyi. Çabalarınız için teşekkür ederim .. Ancak, Mike McCaughan'ın dediği gibi, soru uygulamadan ziyade REST kavramı ile ilgili
Aleks Andreev
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.