REST API En iyi yöntem: Parametre değerleri listesini girdi olarak kabul etme [kapalı]


409

Yeni bir REST API'sini başlatıyoruz ve girdi parametrelerini nasıl biçimlendirmemiz gerektiği konusunda en iyi uygulamalar hakkında bazı topluluk girdileri istedim:

Şu anda API'mız çok JSON merkezli (yalnızca JSON döndürüyor). XML döndürmek isteyip istemediğimize dair tartışma ayrı bir konudur.

API çıktımız JSON merkezli olduğundan, girdilerimizin biraz JSON merkezli olduğu ve bazılarının genel olarak garip olabileceğini düşündüğüm bir yolda ilerliyoruz.

Örneğin, şu anda sahip olduğumuz bir kerede birden fazla ürünün çekilebileceği birkaç ürün ayrıntısı almak için:

http://our.api.com/Product?id=["101404","7267261"]

Bunu basitleştirmeli miyiz:

http://our.api.com/Product?id=101404,7267261

Yoksa JSON girişi kullanışlı mı? Daha fazla acı mı?

Her iki stili de kabul etmek isteyebiliriz, ancak bu esneklik aslında daha fazla karışıklığa ve kafa ağrılarına neden olur mu (sürdürülebilirlik, dokümantasyon, vb.)?

Daha karmaşık bir durum, daha karmaşık girdiler sunmak istediğimiz zamandır. Örneğin, aramada birden fazla filtreye izin vermek istiyorsak:

http://our.api.com/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}

Filtre türlerini (ör. ProductType ve color) aşağıdaki gibi istek adları olarak koymak istemiyoruz:

http://our.api.com/Search?term=pumas&productType=["Clothing","Bags"]&color=["Black","Red"]

Çünkü tüm filtre girdilerini birlikte gruplandırmak istedik.

Sonunda, bu gerçekten önemli mi? Giriş türünün o kadar da önemli olmadığı çok sayıda JSON aracı olabilir.

API istemcilerini AJAX aramaları yapan JavaScript müşterilerimizin hayatlarını kolaylaştırmak için JSON girdilerini takdir edebileceğini biliyorum.

Yanıtlar:


341

Bir Adım Geri

Her şeyden önce, REST bir URI'yi evrensel olarak benzersiz bir kimlik olarak tanımlar. Çok fazla insan URI'lerin yapısına yakalanır ve bu URI'lerin diğerlerinden daha "dinlendirici" olduğu görülür. Bu argüman birisine "Bob" adını vermek "Joe" adını vermekten daha iyidir - her iki isim de "bir kişiyi tanımlama" işini yapar. Bir URI evrensel olarak benzersiz bir isimden başka bir şey değildir .

Bu yüzden REST'in gözünde ?id=["101404","7267261"]daha dinlendirici ?id=101404,7267261ya \Product\101404,7267261da biraz boşuna olup olmadığını tartışmak .

Şimdi, URI'lerin nasıl oluşturulduğunu birçok kez RESTful hizmetindeki diğer konular için genellikle iyi bir gösterge olarak gösterebilir. URI'lerinizde ve genel olarak sorunuzda birkaç kırmızı bayrak var.

Öneriler

  1. Aynı kaynak için birden çok URI ve Content-Location

    Her iki stili de kabul etmek isteyebiliriz, ancak bu esneklik aslında daha fazla karışıklığa ve kafa ağrılarına neden olur mu (sürdürülebilirlik, dokümantasyon, vb.)?

    URI'ler kaynakları tanımlar. Her kaynağın bir adet kanonik URI'si olmalıdır . Bu, iki URI'nin aynı kaynağa işaret edemeyeceğiniz anlamına gelmez, ancak bunu yapmak için iyi tanımlanmış yollar vardır. Hem JSON hem de liste tabanlı formatları (veya başka bir formatı) kullanmaya karar verirseniz, bu formatlardan hangilerinin ana standart URI olduğuna karar vermeniz gerekir . Aynı "kaynağa" işaret eden diğer URI'lara verilen tüm yanıtlar Content-Locationüstbilgiyi içermelidir .

    Analoji ismine bağlı kalmak, birden fazla URI'ye sahip olmak, insanlar için takma adlara sahip olmak gibidir. Mükemmel bir şekilde kabul edilebilir ve çoğu zaman oldukça kullanışlıdır, ancak bir takma ad kullanıyorsam muhtemelen tam adını bilmek istiyorum - o kişiye başvurmanın "resmi" yolu. Bu şekilde birisi "Nichloas Telsa" adlı birinden söz ettiğinde, "Nick" olarak bahsettiğim kişi hakkında konuştuklarını biliyorum.

  2. URI'nizde "Ara"

    Daha karmaşık bir durum, daha karmaşık girdiler sunmak istediğimiz zamandır. Örneğin, aramada birden fazla filtreye izin vermek istiyorsak ...

    Genel bir kuralım, URI'niz bir fiil içeriyorsa, bir şeyin kapalı olduğunun bir göstergesi olabilir. URI'ler bir kaynağı tanımlar, ancak bu kaynağa ne yaptığımızı göstermemelidir . Bu HTTP'nin işi ya da huzurlu terimlerle, "tekdüze arayüzümüz".

    İsim benzetmesini ölü olarak yenmek için, bir URI'de fiil kullanmak, onlarla etkileşim kurmak istediğinizde birinin adını değiştirmek gibidir. Bob ile etkileşime girersem, ona merhaba demek istediğimde Bob'un adı "BobHi" olmaz. Benzer şekilde, Ürünleri "aramak" istediğimizde, URI yapımız "/ Product / ..." yerine "/ Search / ..." olarak değişmemelidir.

İlk Sorunuzu Yanıtlama

  1. ["101404","7267261"]Vs ile ilgili 101404,7267261: Benim önerim, basitlik uğruna JSON sözdiziminden kaçınmaktır (yani kullanıcılarınızın gerçekten gerekmediğinde URL kodlaması yapmasını gerektirmez). API'nızı biraz daha kullanışlı hale getirecektir. Daha da iyisi, diğerlerinin önerdiği application/x-www-form-urlencodedgibi, muhtemelen son kullanıcılarınıza (ör. ?id[]=101404&id[]=7267261) En aşina olacağı için standart biçime gidin . "Güzel" olmayabilir, ancak Pretty URI'ler Kullanılabilir URI'ler anlamına gelmez. Bununla birlikte, ilk noktamı tekrarlamak, sonuçta REST hakkında konuşurken, önemli değil. Üzerinde çok fazla durmayın.

  2. Karmaşık arama URI örneğiniz, ürün örneğinizle aynı şekilde çözülebilir. application/x-www-form-urlencodedBirçok aşina olduğumuz bir standart olduğu için formatı tekrar tavsiye ederim . Ayrıca, iki birleştirme tavsiye ederim.

URI'niz ...

/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}    

URI kodlandıktan sonra URI'niz ...

/Search?term=pumas&filters=%7B%22productType%22%3A%5B%22Clothing%22%2C%22Bags%22%5D%2C%22color%22%3A%5B%22Black%22%2C%22Red%22%5D%7D

Dönüştürülebilir ...

/Product?term=pumas&productType[]=Clothing&productType[]=Bags&color[]=Black&color[]=Red

URL kodlama gerekliliğinden kaçınmanın ve bir şeylerin biraz daha standart görünmesini sağlamanın yanı sıra, şimdi API'yı biraz homojenize ediyor. Kullanıcı, bir Ürünü veya Ürün Listesini (her ikisinin de RESTful terimleriyle tek bir "kaynak" olarak kabul edilir) almak isterse, URI'lerle ilgilendiklerini bilir /Product/....


67
[]Sözdiziminin her zaman desteklenmediğini (ve yaygın olmasına rağmen, URI spesifikasyonunu bile ihlal edebileceğini) takip etmek ve not etmek istedim. Bazı HTTP sunucuları ve programlama dilleri sadece adı tekrar etmeyi tercih edecektir (örneğin productType=value1&productType=value2).
nategood

1
Bu sorguyla ilgili ilk soru .. "/ Arama? Terimi = pumas & filters = {" productType ": [" Giyim "," Çantalar "]," renk ": [" Siyah "," Kırmızı "]}" ... . (productType == clothing || productType == bags) && (color == black || color == red) AMA ÇÖZÜMÜNÜZ: / Product? term = pumas & productType [] = Giyim & productType [] = Çanta & renk [] = Black & color [] = Kırmızı şu anlama geliyor ... Ya (productType == clothing || productType == bags || color == black || color == red) ya da (productType == clothing && productType == bags && color == black && color == red) Bu benim için biraz farklı görünüyor. Yoksa yanlış mı anladım?
Thomas Cheng

2
Gönderi isteğindeki girdiler ne olacak? Bir kaynağı güncelleyip güncellemediğimizi bilmek istedim, o zaman sorgu / filtre ve veriyi standart bir formatta göndermek için kötü bir uygulamadır. örneğin. i API kullanarak kullanıcıya ilgili verileri değiştirmek isterseniz /user/ve vücutta, ben gönderirim { q:{}, d: {} }ile qDB sorgulanan edilecek kullanıcı ile tarafından ve sorgu olarak ddeğiştirilmiş veri olarak.
molekül

1
Liste çok büyük olduğunda ne yaparsınız? URI'nin tarayıcıya bağlı olarak uzunluğu sınırlıdır. Genellikle bir posta isteğine geçtim ve listeyi gövdeye gönderdim. Orada herhangi bir öneriniz var mı?
Troy Cosentino

4
ÇOK büyük olması gerekir (bkz. Stackoverflow.com/questions/417142/… ), ancak evet, en uç durumlarda, isteğin gövdesini kullanmanız gerekebilir. Veri alma için POSTing sorguları RESTafaryalıların tartışmayı sevdikleri şeylerden biridir.
nategood

233

Bir değer listesini URL parametreleri olarak iletmenin standart yolu bunları tekrarlamaktır:

http://our.api.com/Product?id=101404&id=7267261

Birçoğunun tek değer sadeleştirmeleri olmasına rağmen, çoğu sunucu kodu bunu bir değerler listesi olarak yorumlar.

Sınırlandırılmış değerler de uygundur.

Sunucuya JSON göndermeniz gerekiyorsa, URL'de (farklı bir formatta) görmeyi sevmiyorum. Özellikle, URL'lerin boyut sınırlaması vardır (pratikte teorik değilse).

Bazı RESTfully karmaşık bir sorgu yapmak gördüm şekilde iki adımda olduğunu:

  1. POST bir kimlik geri alma (temel olarak bir arama ölçütü kaynağı oluşturma)
  2. GET yukarıdaki kimliğe referansla arama
  3. isteğe bağlı olarak gerekirse sorgu gereksinimlerini SİLİN, ancak gereksinimlerin yeniden kullanılabileceğini unutmayın.

8
Teşekkürler Kathy. Sanırım seninleyim ve URL'de JSON'u görmekten gerçekten hoşlanmıyorum. Ancak, doğal bir GET işlemi olan bir arama için bir gönderi yapma hayranı değilim. Bunun bir örneğine işaret edebilir misiniz?
whatupwilly

1
Sorgular basit parametreler olarak çalışabiliyorsa, bunu yapın. Kaynak, geri kalan tartışma posta listesinden alındı: tech.groups.yahoo.com/group/rest-discuss/message/11578
Kathy Van Stone

2
Sadece iki kaynak göstermek istiyorsanız, James Westgate'in cevabı daha tipik
Kathy Van Stone

Bu doğru cevap. Yakın gelecekte OData veya bunun gibi bir şey tarafından desteklenen bazı filtre = id (a, b, c, ...) göreceğimize eminim.
Bart Calixto

Akka HTTP böyle çalışıyor
Joan

20

İlk:

Bence 2 yolla yapabilirsin

http://our.api.com/Product/<id> : sadece bir kayıt istiyorsanız

http://our.api.com/Product : tüm kayıtları istiyorsanız

http://our.api.com/Product/<id1>,<id2> : James'in önerdiği gibi, Ürün etiketinden sonra gelenler bir parametre olduğu için bir seçenek olabilir

Ya da en çok sevdiğim:

Sen kullanabilirsiniz uygulama durumu motoru olarak Hypermedia dinlendirici WS (HATEOAS) mülkiyet ve bir çağrı yapmak http://our.api.com/Producteşdeğer adresler dönmelidir http://our.api.com/Product/<id>ve bundan sonra diyoruz.

İkinci

URL çağrılarında sorgular yapmanız gerektiğinde. HATEOAS'ı tekrar kullanmanızı öneririm.

1) için bir çağrı yapın http://our.api.com/term/pumas/productType/clothing/color/black

2) almak için bir çağrı yapın http://our.api.com/term/pumas/productType/clothing,bags/color/black,red

3) (HATEOAS kullanarak) ` http://our.api.com/term/pumas/productType/ -> url'lerini almak için tüm olası kıyafet url'lerini alın -> istediklerinizi arayın (giyim ve çantalar) - > olası renk URL'lerini alın -> istediklerinizi arayın


1
Birkaç gün önce benzer bir duruma getirildim, filtrelenmiş (büyük) bir nesne listesi almak için (HATEOAS) bir dinlenme API'sini ayarlamak zorunda kaldım ve sadece ikinci çözümünüzü seçtim. Api'yi her biri için tekrar tekrar aşırı hatırlamak değil mi?
Samson

Gerçekten sisteminize bağlıdır .... Eğer birkaç "seçenek" ile basit bir tane ise muhtemelen aşırı olmalıdır. Bununla birlikte, gerçekten büyük listeleriniz varsa, hepsini büyük bir çağrıda yapmak gerçekten zahmetli hale gelebilir, ayrıca API'nız herkese açıksa, kullanıcılar için karmaşık olabilir (özel bir liste ise daha kolay olmalıdır ... sadece tanıdığınız kullanıcılara öğretin). Alternatif olarak, ileri düzey kullanıcılar için hem stil, hem de HATEOAS ve "huzurlu bir dizi" çağrısı uygulayabilirsiniz
Diego Dias

Raylarda huzurlu bir api web servisi kuruyorum ve yukarıdakiyle aynı url yapısını izlemem gerekiyor ( our.api.com/term/pumas/productType/clothing/color/black ). Ancak rotaları buna göre nasıl yapılandıracağından emin değilim.
rubyist

denetleyicileriniz terim, productType ve renk nedir? Eğer öyleyse, yapmanız gereken: kaynaklar: term do resources: productType do resources: color end end
Diego Dias

productType ve renk parametrelerdir. Bu yüzden ürün paramleri Tip giyim ve giyim
paramları

12

RFC 6570'i kontrol etmek isteyebilirsiniz . Bu URI Şablonu spesifikasyonu, URL'lerin parametreleri nasıl içerebileceğine dair birçok örnek gösterir.


1
Bölüm 3.2.8 uygulanabilir olan bölüm gibi görünmektedir. Her ne kadar bunun sadece önerilen bir standart olduğunu ve bu noktanın ötesine geçmediğini belirtmek gerekir.
Mike Post

3
@MikePost Artık IETF "standartlar takibi" belgeleri için iki adımlı bir olgunluk sürecine geçtiğine göre, 6570'in "İnternet Standardı" na geçmeden önce birkaç yıl daha böyle kalmasını bekliyorum. tools.ietf.org/html/rfc6410 Spesifikasyon son derece kararlıdır, birçok uygulaması vardır ve yaygın olarak kullanılmaktadır.
Darrel Miller

Ah bu değişimin farkında değildim. (Veya, TIL IETF artık daha makul.) Teşekkürler!
Mike Post

8

İlk durum:

Normal bir ürün araması şöyle görünür

http://our.api.com/product/1

Bu yüzden bunu yapabilmeniz için en iyi uygulamanın olacağını düşünüyorum

http://our.api.com/Product/101404,7267261

İkinci Vaka

Querystring parametreleriyle arama yapın - bunun gibi. Terimleri kullanmak yerine AND ve OR ile birleştirmek cazip olurdu [].

PS Bu öznel olabilir, bu yüzden rahat hissettiğiniz şeyi yapın.

Verileri url'ye koymanın nedeni, bağlantının bir siteye yapıştırılabilmesi / kullanıcılar arasında paylaşılabilmesidir. Bu bir sorun değilse, elbette bunun yerine bir JSON / POST kullanın.

EDIT: Yansıtma üzerine bu yaklaşım bileşik anahtarı olan bir varlık için uygun olduğunu düşünüyorum, ancak birden çok varlık için bir sorgu değil.


3
Tabii ki, her iki örnekte de /, URI bir koleksiyona değil, bir kaynağa hitap ettiğinden , takip orada olmamalıdır.
Lawrence Dol

2
Ben her zaman bir REST kullanımında HTTP fiilleri, belirli eylemler yapmak oldu ve bu rehberlik hattı oldu: GET: alma / okuma nesnesi, POST oluşturma nesnesi, PUT mevcut nesneyi güncelleme ve bir nesneyi SİLME. Yani bir şey almak için bir POST kullanmak olmaz. Özellikle (filtre) bir nesne listesi istiyorum, ben url parametreleri (virgül ile ayrılmış iyi görünüyor) bir liste ile bir GET yapmak istiyorum
Alex

1

Tamamlandı ve ihtiyaçlarınızı memnun gibi görünüyordu nategood cevap ile taraf olacak. Yine de, ben birden çok (1 veya daha fazla) kaynağı bu şekilde tanımlamak için bir yorum eklemek istiyorum:

http://our.api.com/Product/101404,7267261

Bunu yaparken:

Aşağıdaki isteği yaparsam istemcileri sezgisel olan bir dizi olarak yanıtınızı yorumlamaya zorlayarak istemcileri karmaşıklaştırın :http://our.api.com/Product/101404

Tüm ürünleri almak için bir API ve 1 veya daha fazla almak için yukarıdaki API ile yedek API'ler oluşturun . Bir kullanıcıya UX uğruna 1 sayfadan daha fazla ayrıntı göstermemeniz gerektiğinden, 1'den fazla kimliğe sahip olmanın işe yaramayacağını ve yalnızca ürünleri filtrelemek için kullanılacağına inanıyorum.

Bu sorunlu olmayabilir, ancak tek bir varlık döndürerek (yanıtınızın bir veya daha fazla içerip içermediğini doğrulayarak) ya da sunucu tarafını kendiniz ele almanız veya istemcilerin bunu yönetmesine izin vermeniz gerekir.

Misal

Ben bir kitap sipariş etmek istiyorum Şaşırtıcı . Tam olarak hangi kitabın olduğunu biliyorum ve Korku kitapları için gezinirken listede görüyorum:

  1. 10000 muhteşem çizgi, 0 muhteşem test
  2. İnanılmaz canavarın dönüşü
  3. Harika kodu çoğaltalım
  4. Sonun İnanılmaz Başlangıcı

İkinci kitabı seçtikten sonra, listenin kitap kısmını ayrıntılandıran bir sayfaya yönlendirildim:

--------------------------------------------
Book #1
--------------------------------------------
    Title: The return of the amazing monster
    Summary:
    Pages:
    Publisher:
--------------------------------------------

Yoksa bana sadece o kitabın tüm ayrıntılarını veren bir sayfada mı?

---------------------------------
The return of the amazing monster
---------------------------------
Summary:
Pages:
Publisher:
---------------------------------

Benim fikrim

Bu kaynağın ayrıntılarını alırken teklik garanti edildiğinde ID yol değişkeninde kullanmanızı öneririm. Örneğin, aşağıdaki API'lar belirli bir kaynağın ayrıntılarını almanın birden fazla yolunu önerir (bir ürünün benzersiz bir kimliği olduğunu ve o ürünün spesifikasyonunun benzersiz bir adı olduğunu ve yukarıdan aşağıya gidebileceğinizi varsayalım):

/products/{id}
/products/{id}/specs/{name}

Birden fazla kaynağa ihtiyacınız olduğu anda, daha geniş bir koleksiyondan filtreleme yapmanızı öneririm. Aynı örnek için:

/products?ids=

Tabii ki, dayatılmadığı için bu benim görüşüm.

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.