İç içe REST URL'leri ve üst kimlik, hangisi daha iyi tasarım?


20

Tamam, iki kaynağımız var: Albumve Song. İşte API:

GET,POST /albums
GET,POST /albums/:albumId
GET,POST /albums/:albumId/songs
GET,POST /albums/:albumId/songs/:songId

Bazı şarkılardan nefret ettiğimizi biliyoruz, Susyörneğin. Nerede searchharekete geçmeliyiz?

Başka bir soru. Tamam, şimdi daha gerçek. Albüm 1'i açıp tüm şarkıları yüklüyoruz. JS nesneleri yaratıyoruz, her biri şarkı verilerini tutuyor ve şöyle birkaç yöntemi var: remove, update.

Şarkı nesnesinin kimliği, adı ve malzemesi vardır, ancak hangi üst öğeye ait olduğu hakkında hiçbir fikri yoktur, çünkü şarkıların listesini sorguya göre alırız ve her birinin üst kimliğini döndürmek o kadar iyi olmaz. Yanlış mıyım?

Yani, birkaç çözüm görüyorum, ama gerçekten emin değilim.

  1. Üst kimliği isteğe bağlı yap - get-parametresi olarak. Şu anda kullandığım bu yaklaşım, ama çirkin olduğunu hissediyorum.

    List,Create /songs?album=albumId
    Update,Delete /songs/:songId
    Get /songs/?name=susy # also, solution for first question
    
  2. Hibrid. OPTIONSMeta veri almak için sorgu gerçekleştirmek için albüm kimliğine ihtiyacımız olduğundan artık bu kadar kullanışlı .

    List,Create /album/:albumId/songs
    Update,Delete /songs/:songId
    POST /songs/search # also, solution for first question
    
  3. Her kaynak örneğiyle tam URL döndürün. API aynıdır, ancak bunun gibi şarkılar alacağız:

    id: 5
    name: 'Elegy'
    url: /albums/2/songs/5
    

    Bu yaklaşımın HATEOAS olduğunu duydum.

  4. Yani ... Ebeveyn kimliği sağlamak için

    id: 5
    name: 'Elegy'
    albumId: 2
    

Hangisi daha iyi? Ya da belki aptalım? Bazı tavsiyeler atın çocuklar!

Yanıtlar:


31

Nerede arama işlemi yapmalıyız?

In GET /search/:text. Bu, ait olduğu albümü içeren her eşleşmeyi içeren bir JSON dizisi döndürür. Bu mantıklıdır, çünkü müşteri parçanın kendisiyle değil, tüm albümle ilgilenebilir (adını hatırladığınızla aynı albümde olduğuna inandığınız bir şarkı aradığınızı hayal edin).

her birinin üst kimliğini döndürmek iyi olmayacaktır. Yanlış mıyım?

Tek tek parçalar albümü içerebilir. Bu, bir albümü bir albümden veya aramadan (burada albüm yok) alabiliyorsanız parça sunumunun aynı olmasını sağlar.

Hangisi daha iyi?

Daha önce belirtildiği gibi, albüm de dahil olmak mantıklı. Üçüncü nokta (göreli URI ile) bazı durumlarda ilginç olsa da (URI'nin nasıl oluşturulması gerektiğini düşünmek zorunda değilsiniz), albümü açıkça belirtmemenin bir dezavantajı vardır. Dördüncü nokta bunu düzeltir. Yanıtta göreli URI'ya sahip olmanın faydasını görürseniz, 3. ve 4. noktaları birleştirebilirsiniz.

Ya da belki aptalım?

İyi URI'leri seçmek, özellikle tek bir doğru cevap olmadığı için kolay bir iş değildir. İstemciyi API ile aynı zamanda geliştirirseniz, API'nın nasıl kullanılabileceğini daha iyi görselleştirmenize yardımcı olabilir. Bununla birlikte, diğer insanlar API'yı geliştirirken düşünmediğiniz diğer kullanımları tercih edebilir.

Sorunlu olabilecek bir husus, verileri dahili olarak nasıl düzenlediğinizdir, yani bir hiyerarşi kullanmaktır. Yorumunuzdan, neye cevap vermesi gerektiğini merak ediyorsunuz GET /artist/1/album/10/song/3/comment/23, bu da çok ağaç odaklı bir vizyon gösteriyor. Bu, sistemi daha sonra genişletirken birkaç soruna yol açabilir. Örneğin:

  • Bir şarkının albümü yoksa ne olur?
  • Bir albümde birden fazla sanatçı varsa ne olur?
  • Albümlere yorum yapmayı mümkün kılan bir özellik eklemek isterseniz ne olur?
  • Yorumların yorumlanması gerekiyorsa ne olur?
  • vb.

Bu aslında blogumda açıkladığım problem : bir ağaç temsilinin birçok durumda etkili bir şekilde kullanılması için çok fazla sınırlama var.

Hiyerarşiyi yok ederseniz ne olur? Bakalım.

  1. GET /albums/:albumIdalbümle ilgili meta bilgileri (yayınlandığı yıl veya albüm kapağını gösteren JPEG URI'si gibi) ve bir parça dizisini içeren bir JSON döndürür. Örneğin:

    GET /albums/151
    {
        "id": 151,
        "gid": "dbd3cec7-b927-423f-894b-742c4c7b54ce",
        "name": "Yellow Submarine",
        "year": 1969,
        "genre": "Psychedelic rock",
        "artists": ["John Lennon", "Paul McCartney", ...],
        "tracks": [
            {
                "id": 90224,
                "title": "Yellow Submarine",
                "length": "2:40"
            },
            {
                "id": 83192,
                "title": "Only a Northern Song",
                "length": "3:24"
            }
            ...
        ]
    }
    

    Neden her parçanın uzunluğunu dahil ediyorum? Çünkü bir albüm gösteren istemcinin parçaları başlığa göre listeleyerek ilgilendiğini, ancak her parçanın uzunluğunu da gösterdiğini düşünüyorum - çoğu müşteri bunu yapıyor. Öte yandan, bestecileri veya sanatçıları her parça için göstermeyebilirim, çünkü bu bilgilerin bu düzeyde gerekli olmadığına karar verdim. Açıkçası, seçimleriniz farklı olabilir.

  2. GET /tracks/:trackIdbelirli bir parça hakkındaki bilgileri döndürür. Artık bir hiyerarşi olmadığı için albümü veya sanatçıyı tahmin etmenize gerek yok: gerçekten bilmeniz gereken tek şey parçanın kendisinin tanımlayıcısı.

    Ya da belki de değil? Ya adıyla belirtebilirseniz ne olur GET /tracks/:trackName?

    GET /tracks/Only%20a%20Northern%20Song
    {
        "id": 83192,
        "gid": "8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b",
        "title": "Only a Northern Song",
        "writers": ["George Harrison"],
        "artists": ["John Lennon", "Paul McCartney", "Ringo Starr"],
        "length": "3:24",
        "record-date": 1967,
        "albums": [151, 164],
        "soundtrack": {
            "uri": "http://audio.example.com/tracks/static/83192.mp3",
            "alias": "Beatles - Only a Northern Song.mp3",
            "length-bytes": 3524667,
            "allow-streaming": true,
            "allow-download": false
        }
    }
    

    Şimdi daha yakından bakın albums; ne görüyorsun? Doğru, bir değil iki albüm. Bir hiyerarşiniz varsa, bunu yapamazsınız (kaydı çoğaltmadıkça).

  3. GET /comments/:objectGid. Yanıtlarda çirkin GUID'leri tespit etmiş olabilirsiniz. Bu GUID'ler albümlere, sanatçılara veya parçalara uygulanabilecek görevleri gerçekleştirmek için veritabanındaki varlığı tanımlamayı mümkün kılar. Yorum yapmak gibi.

    GET /comments/8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b
    [
        {
            "author": {
                "id": 509931,
                "display-name": "Arseni Mourzenko"
            },
            "text": "What a great song! (And I'm proud of the usefulness of my comment)",
            "concerned-object": "/tracks/83192"
        }
    ]
    

    Yorum, ilgili nesneye referans verir ve yoruma bağlamı dışında erişirken (örneğin, en son yorumları denetlerken GET /comments/latest) ona gitmeyi mümkün kılar .

Bunun, API'nizde herhangi bir hiyerarşi biçiminden kaçınmanız gerektiği anlamına gelmediğini unutmayın. Mantıklı olduğu durumlar vardır. Kural olarak:

  • Kaynak üst kaynağının bağlamı dışında bir anlam ifade etmiyorsa, hiyerarşi kullanın.

  • Kaynak (1) tek başına veya (2) farklı türdeki ana kaynaklar bağlamında yaşayabilirse veya (3) birden fazla üst öğeye sahipse, hiyerarşi kullanılmamalıdır.

Örneğin, bir dosyanın satırları bir dosyanın bağlamı dışında bir anlam ifade etmez, bu nedenle:

GET /file/:fileId

ve:

GET /file/:fileId/line/:lineIndex

iyi.


Evet, aramadan, tam albüm bilgisini de geri verebilirim, başka bir kaynak yapar - SongSearchResultiyi, sanırım. Peki, URL'ler ne olacak? parentIDHer nesneyi sağlamalı ve GET parametresi veya URL'nin normal parçası olarak kullanmalı mıyım ? Ya derinliğim> 2 ise? /artist/1/album/10/song/3/comment/23- sanatçı, albüm ve şarkının her kimliğini commentnesnede sağlamak delilik , ama bunun bir yol olduğunu duydum, ama zor değil mi ?!
dt0xff

@ dt0xff: Cevabımı düzenledim. Sanırım şimdi derinliğin nasıl önlenebileceğine dair net bir görüntü vermeli.
Arseni Mourzenko

Evet, artık her bir kaynak için giriş noktasını (satır veya başka bir işlevsel şey hariç) url tarafından üst öğeye eklemeden uygulamak çok daha kolay. Teşekkür ederim, beni seçimimin doğru olduğuna ikna ettin ve "ortak yaklaşım" (gerçekten, birçok iç içe şeyler .. restangularüzerine inşa edilmiş) o kadar iyi değil.
dt0xff

Mükemmel cevap. Yine de birkaç itirazım var. "Bir albümde birden fazla sanatçı varsa ne olur?" İkili ilişki URI -> kaynağı doğru-benzersiz (çok-bire) olduğundan farklı URI'ler aynı kaynağı tanımlayabilir . Böylece URI'ler /artists/foo/albums/quxve /artists/bar/albums/quxaynı albüm kaynağını mükemmel bir şekilde tanımlayabilirler. Başka bir deyişle, bir URI'deki yol bileşeni, bir ağaç hiyerarşisini değil, bir grafik hiyerarşisini temsil eder , bu da onu sadece kategorileri değil aynı zamanda etiketleri temsil etmek için de uygun hale getirir.
Maggyero

1
… "Bu aslında blogumda açıkladığım problem : bir ağaç temsilinin birçok durumda etkili bir şekilde kullanılması için çok fazla sınırlama var." Yani hayır, bu bir sorun değil. "Albümlere yorum yapmayı mümkün kılan bir özellik eklemek isterseniz ne olur?" Bu da bir sorun değil: /artists/foo/albums/qux/comments/7. "Ya yorumların yorumlanması gerekiyorsa?" Aynı şekilde: /artists/foo/albums/qux/song/5/comments/2/comments/8.
Maggyero
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.