REST Kompleksi / Kompozit / İç İçe Kaynaklar [kapalı]


177

REST tabanlı bir API kavramları ele en iyi yolu etrafında başımı sarmaya çalışıyorum. Başka kaynak içermeyen düz kaynaklar sorun değil. Sorun yaşadığım yer karmaşık kaynaklar.

Mesela bir çizgi roman için kaynağım var. ComicBookÜzerinde özelliklerin her türlü gibi vardır author, issue number, datevb

Bir çizgi romanda da 1..nkapak listesi var . Bu kapaklar karmaşık nesnelerdir. Kapak hakkında birçok bilgi içerirler: sanatçı, bir tarih ve hatta kapağın 64 kodlu bir görüntüsü.

Bir süre GETiçin ComicBooksadece çizgi romanı ve base64'ed görüntüleri de dahil olmak üzere tüm kapakları iade edebilirim. Muhtemelen tek bir çizgi roman almak için büyük bir sorun değil. Ancak, bir tablodaki sistemdeki tüm çizgi romanları listelemek isteyen bir istemci uygulaması oluşturduğumu varsayalım.
Tablo, ComicBookkaynaktan birkaç özellik içerecektir , ancak kesinlikle tablodaki tüm kapakları görüntülemek istemeyeceğiz. Her biri birden çok kapağı olan 1000 çizgi roman döndürmek, telden son derece gülünç miktarda veri gelmesine neden olur, bu durumda son kullanıcı için gerekli değildir.

İçgüdüm Coverbir kaynak yapmak ve ComicBookkapaklar içermek. Şimdi Coverbir URI. GETşimdi çizgi roman üzerinde çalışıyor, büyük Coverkaynak yerine her kapak için bir URI geri gönderiyoruz ve müşteriler Kapak kaynaklarını istedikleri gibi alabilirler.

Şimdi yeni çizgi roman yaratmakla ilgili bir sorunum var. Kuşkusuz Comic, bir iş oluştururken en azından bir kapak oluşturmak isteyeceğim , aslında bu bir iş kuralı.
Bu yüzden şimdi, ben de ilk olarak bir göndererek iş kuralları uygulamak için müşterilerine takılıp zorlamak ediyorum Covero zaman, bu kapak için URI alma, POSTbir ing ComicBooklistede URI, ya da benim bununla POSTilgili ComicBookfarklı bir seyir kaynak alır o tükürür daha dışarı. Giden kaynakların bağımlı kaynaklara referanslar içerdiği , gelen kaynaklar POSTve GETbunların derin kopyalarıdır GET.

CoverBen bazı durumlarda adres kapakları yönde isterdim istemci olarak eminim çünkü kaynak muhtemelen her durumda gereklidir. Dolayısıyla, bağımlı kaynağın boyutuna bakılmaksızın, sorun genel bir biçimde mevcuttur. Genel olarak, istemciyi bu kaynakların nasıl oluşturulduğunu "bilmek" zorunda bırakmadan karmaşık kaynakları nasıl ele alırsınız?


kullanarak yapar RESTFUL SERVİS KEŞİF mantıklı?
treecoder

1
HATEAOS'a bağlı kalmaya çalışıyorum ki, bence, böyle bir şey kullanmaya karşı karşı çıkıyor ama bir bakacağım.
jgerman

Aynı ruhla farklı bir soru. Ancak sahiplik, önerilen çözümünüzden farklıdır (Sorudaki çözüm). stackoverflow.com/questions/20951419/…
Wes

Yanıtlar:


64

@ray, mükemmel tartışma

@jgerman, sadece REST olduğu için kaynakların POST'tan taş olarak ayarlanması gerektiği anlamına gelmediğini unutmayın.

Bir kaynağın herhangi bir temsiline dahil etmeyi seçtiğiniz şey size bağlıdır.

Ayrı ayrı başvurulan kapaklar için durumunuz, yalnızca alt kaynakları (kapaklar) çapraz referans verilebilecek bir ana kaynak (çizgi roman) oluşturulmasıdır. Örneğin, yazarlara, yayıncılara, karakterlere veya kategorilere ayrı ayrı referanslar vermek isteyebilirsiniz. Bu kaynakları ayrı ayrı veya alt kaynak olarak referans alan çizgi romandan önce oluşturmak isteyebilirsiniz. Alternatif olarak, üst kaynak oluşturulduktan sonra yeni alt kaynaklar oluşturmak isteyebilirsiniz.

Kapaklara ilişkin özel durumunuz, bir kapağın gerçekten bir çizgi roman gerektirdiği için biraz daha karmaşıktır ve bunun tersi de geçerlidir.

Ancak, bir e-posta iletisini kaynak olarak ve gelen adresini alt kaynak olarak kabul ediyorsanız, yine de gönderen adresine ayrı ayrı başvurabilirsiniz. Örneğin, adreslerden hepsini alın. Veya adresinden bir öncekiyle yeni bir mesaj oluşturun. E-posta REST olsaydı, çapraz referanslı birçok kaynağın mevcut olabileceğini kolayca görebilirsiniz: / alınan mesajlar, / taslak mesajlar, / adreslerden, / adreslere, / adresler, / konular, / ekler / klasörler / etiketleri, / kategorileri, / etiketleri, vd.

Bu eğitici çapraz referanslı kaynaklara harika bir örnek sunmaktadır. http://www.peej.co.uk/articles/restfully-delicious.html

Bu, otomatik olarak oluşturulan veriler için en yaygın modeldir. Örneğin, sunucu tarafından oluşturulduğu için yeni kaynak için bir URI, kimlik veya oluşturma tarihi göndermezsiniz. Yine de, yeni kaynağı geri aldığınızda URI'yi, kimliği veya oluşturma tarihini alabilirsiniz.

İkili veri durumunda bir örnek. Örneğin, ikili verileri alt kaynaklar olarak göndermek istiyorsunuz. Üst kaynağı aldığınızda, bu alt kaynakları aynı ikili veriler veya ikili verileri temsil eden URI'ler olarak temsil edebilirsiniz.

Formlar ve parametreler, kaynakların HTML sunumlarından zaten farklıdır. URL ile sonuçlanan bir ikili / dosya parametresi yayınlamak bir uzatma değildir.

Yeni bir kaynak (/ comic-books / new) için form aldığınızda veya bir kaynağı düzenleme formunu aldığınızda (/ comic-books / 0 / edit), kaynağın forma özgü bir temsilini istersiniz. İçerik türü "application / x-www-form-urlencoded" veya "multipart / form-data" ile kaynak koleksiyonuna gönderirseniz, sunucudan bu tür gösterimini kaydetmesini istersiniz. Sunucu, kaydedilen HTML temsiliyle veya her neyse yanıt verebilir.

Ayrıca, API veya benzeri bir amaçla, HTML, XML veya JSON temsilinin kaynak koleksiyonuna gönderilmesine izin vermek isteyebilirsiniz.

Ayrıca, çizgi romandan sonra yayınlanan kapakları da dikkate alarak, ancak çizgi romanların bir kapağa sahip olmasını gerektiren kaynaklarınızı ve iş akışınızı tanımladığınız şekilde temsil etmek de mümkündür. Aşağıdaki örnek.

  • Gecikmeli kapak oluşturmaya izin verir
  • Gerekli kapakla çizgi roman oluşturmaya izin verir
  • Kapaklara çapraz referans verilmesini sağlar
  • Birden çok kapağa izin verir
  • Taslak çizgi roman oluştur
  • Taslak çizgi roman kapakları oluşturma
  • Taslak çizgi roman yayınla

GET / çizgi roman
=> 200 Tamam, Tüm çizgi romanları al.

GET / çizgi romanlar / 0
=> 200 OK, Kapaklı çizgi roman (id: 0) alın (/ covers / 1, / covers / 2).

GET / çizgi romanlar / 0 / kapaklar
=> 200 Tamam, Çizgi roman için kapaklar al (id: 0).

GET / covers
=> 200 OK, Tüm kapakları al.

GET / kapaklar / 1
=> 200 Tamam, Çizgi romanla (/ çizgi romanlar / 0) kapak (id: 1) alın.

GET / çizgi romanlar / yeni
=> 200 Tamam, çizgi roman oluşturmak için form al (form: POST / taslak-çizgi romanlar).

POST / draft-comic-books
title = foo
yazar = boo
yayıncı = goo
yayınlandı = 2011-01-01
=> 302 Bulundu, Yer: / draft-comic-books / 3, Çizgi roman taslağına yeniden yönlendir (id: 3) kapaklar (ikili).

GET / taslak-çizgi romanlar / 3
=> 200 Tamam, Kapaklı taslak çizgi roman (id: 3) alın.

GET / taslak-çizgi romanlar / 3 / kapaklar
=> 200 Tamam, Taslak çizgi roman için kapaklar alın (/ taslak-çizgi roman / 3).

GET / taslak-çizgi romanlar / 3 / kapaklar / yeni
=> 200 Tamam, Taslak çizgi roman için kapak oluşturmak için form al (/ taslak-çizgi roman / 3) (form: POST / taslak-çizgi romanlar / 3 / kapaklar).

POST / taslak-çizgi romanlar / 3 / kapaklar
cover_type = front
cover_data = (ikili)
=> 302 Bulundu, Yer: / draft-comic-books / 3 / kapaklar, Taslak çizgi roman için yeni kapağa yönlendir (/ draft-comic Paket / 3 / kapakları / 1).

GET / taslak-çizgi romanlar / 3 / yayınla
=> 200 Tamam, Taslak çizgi roman yayınlamak için form al (id: 3) (form: POST / yayınlanan-çizgi romanlar).

POST / yayımlanmış-çizgi romanlar
başlık = foo
yazar = boo
yayıncı = goo
yayınlandı = 2011-01-01
cover_type = ön
cover_data = (ikili)
=> 302 Bulundu, Yer: / comic-books / 3, Yayınlanan çizgi romana yönlendir (id: 3) kapaklı.


Ben tam bir acemi ve aceleyle öğrenmeye çalışıyorum. Bu son derece yararlı buldum. Ancak, bugün okuduğum diğer bloglarda vs. GET'in bir operasyon (özellikle de idempotent olmayan bir operasyon) gerçekleştirmek için kullanılması kaşlarını çattı. Öyleyse POST / taslak-çizgi romanlar / 3 / yayınlamamalı mı?
Gary McGill

3
@GaryMcGill Örneğinde, / draft-comic-books / 3 / publish sadece bir HTML formu döndürür (herhangi bir veriyi değiştirmez).
Olivier Lalonde

@Olivier doğru. Yayınlama sözcüğü, formun ne yaptığını göstermek için vardır. Ancak, fiilleri HTTP yöntemleriyle sınırlı tutmak istediğiniz için, yayınlanan çizgi romanlar için bir kaynak yayınlamalısınız. ... Bu bir web sitesi olsaydı, formun bir şey yayınlaması için bir URI'ye ihtiyacınız olabilir. ... Ancak, yayınlama eylemi çizgi roman sayfasında yalnızca tek bir düğme olsaydı, bu tek düğmeli form doğrudan / yayımlanmış-çizgi romanlar URI'sine gönderilebilir.
Alex

@Alex, POST isteğinde, bunun yerine 201 üstbilgi, yeni kaynak URL'sini yanıt üstbilgilerinde Konum olarak döndürürdüm.
ismriv

2
@Stephane, yönlendirmeler kontrolörler için her şeyi kolaylaştırıyor. Bir API için bile, oluşturma denetleyicisinin yeni içeriğin konumunu döndürmesini ve ardından gösteri denetleyicisinin yeni içeriğin görüntülenmesini sağlamasına izin vermek daha kolaydır. Bununla birlikte, API istemcisinin yalnızca içeriği alması ve yönlendirmelerle uğraşmaması daha iyi / basittir.
Alex

45

Kapakları kaynak olarak ele almak kesinlikle REST'in ruhunda, özellikle HATEOAS'ta. Yani evet, kapaklar için bir dizi URI içeren özellikler içeren kitap 1'in bir temsilini vermek GETiçin bir istek http://example.com/comic-books/1. Çok uzak çok iyi.

Sorunuz çizgi roman oluşturma ile nasıl başa çıkacağınızdır. İş kuralınız bir kitabın 0 veya daha fazla kapsama sahip olması durumunda, sorun olmaz:

POST http://example.com/comic-books

kapaksız çizgi roman verileri ile yeni bir çizgi roman oluşturacak ve sunucu tarafından oluşturulan kimliği geri göndereceğiz (8 olarak geri döndüğünü varsayalım) ve şimdi buna böyle kapaklar ekleyebilirsiniz:

POST http://example.com/comic-books/8/covers

varlık gövdesinde kapak ile.

Şimdi, iş kuralınız her zaman en az bir kapak olması gerektiğini söylüyorsa ne olacağı konusunda iyi bir sorunuz var. İlki sorunuzda belirlediğiniz bazı seçenekler şunlardır:

  1. Öncelikle bir kapak oluşturulmasını zorlayın, şimdi esas olarak kapağı bağımlı olmayan bir kaynak haline getirin veya ilk kapağı çizgi romanı oluşturan POST'un varlık gövdesine yerleştirin. Söylediğiniz gibi, oluşturmanız için POST yaptığınız temsil, GET aldığınız gösterimden farklı olacaktır.

  2. Birincil veya ilk veya tercih edilen veya başka şekilde belirlenmiş bir kapak kavramını tanımlayın. Bu muhtemelen bir modelleme hack'idir ve bunu yapsaydınız, bir teknolojiye uymak için nesne modelinizi (kavramsal veya iş modeliniz) ayarlamak gibi olurdu. Harika bir fikir değil.

Bu iki seçeneği sadece kapaksız çizgi romanlara izin vermemeye karşı tartmalısınız.

Üç seçenekten hangisini almalısınız? Durumunuz hakkında çok fazla şey bilmeden, ancak genel 1. kaynak bağımlı soruya cevap verin, şunu söyleyebilirim:

  • RESTful hizmet katmanı için 0..N ile gidebilirsiniz, harika. Belki de RESTful SOA'nız arasındaki bir katman, en az bir tane gerekliyse daha fazla iş kısıtlamasını kaldırabilir. (Bunun nasıl görüneceğinden emin değilim ama keşfetmeye değer olabilir .... son kullanıcılar genellikle SOA'yı zaten görmezler.)

  • Bir 1.N kısıtlamasını modellemeniz gerekiyorsa, kendinize kapakların sadece paylaşılabilir kaynaklar olup olmayacağını, diğer bir deyişle çizgi roman dışındaki şeylerde var olup olmayacağını sorun. Artık bunlar bağımlı kaynaklar değil ve önce bunları oluşturabilir ve POST'unuzda çizgi romanlar oluşturan URI'ler sağlayabilirsiniz.

  • 1. ve N'ye ihtiyacınız varsa ve kapaklar bağımlı kalırsa, POST'taki sunumları korumak ve aynı şekilde almak ya da aynı yapmak için içgüdülerinizi rahatlatın.

Son öğe şu şekilde açıklanmaktadır:

<comic-book>
  <name>...</name>
  <edition>...</edition>
  <cover-image>...BASE64...</cover-image>
  <cover-image>...BASE64...</cover-image>
  <cover>...URI...</cover>
  <cover>...URI...</cover>
</comic-book>

POST yaptığınızda, mevcut urislere sahipseniz (diğer kitaplardan ödünç aldınız) ancak bir veya daha fazla başlangıç ​​resmi koyduğunuzda izin verirsiniz. Bir kitap oluşturuyorsanız ve varlığınızın ilk kapak resmi yoksa, 409 veya benzeri bir yanıt gönderin. GET'te URI'leri döndürebilirsiniz.

Temel olarak POST ve GET temsillerinin "aynı" olmasına izin veriyorsunuz, ancak GET'te kapak resmini "kullanmamayı" veya POST'ta kapamayı seçiyorsunuz. Umarım mantıklıdır.

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.