Verschachtelte REST-URLs und übergeordnete ID, was ist besseres Design?


19

Okay, wir haben zwei Ressourcen: Albumund Song. Hier ist API:

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

Wir wissen, dass wir ein Lied hassen, es heißt Susyzum Beispiel. Wo sollten wir searchMaßnahmen ergreifen?

Eine andere Frage. Okay, jetzt ist es realer. Wir öffnen Album 1 und laden alle Songs. Wir erstellen JS-Objekte, jedes enthält Songdaten und hat einige Methoden wie diese: remove, update.

Song-Objekt hat ID, Name und Zeug, hat aber keine Ahnung, zu welchem ​​Elternteil es gehört, da wir die Liste der Songs per Abfrage abrufen und es nicht so gut ist, Eltern-IDs mit jedem so zurückzugeben. Liege ich falsch?

Ich sehe also nur wenige Lösungen, bin mir aber nicht sicher.

  1. Machen Sie die Eltern-ID optional - als get-Parameter. Diesen Ansatz verwende ich derzeit, aber ich halte ihn für hässlich.

    List,Create /songs?album=albumId
    Update,Delete /songs/:songId
    Get /songs/?name=susy # also, solution for first question
    
  2. Hybrid. Es ist jetzt so praktisch, da wir die Album-ID benötigen, um eine OPTIONSAbfrage zum Abrufen von Metadaten durchzuführen .

    List,Create /album/:albumId/songs
    Update,Delete /songs/:songId
    POST /songs/search # also, solution for first question
    
  3. Geben Sie für jede Ressourceninstanz die vollständige URL zurück. API ist das gleiche, aber wir werden Songs wie folgt bekommen:

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

    Ich habe gehört, dieser Ansatz heißt HATEOAS.

  4. Also ... Übergeordnete ID angeben

    id: 5
    name: 'Elegy'
    albumId: 2
    

Welches ist besser? Oder vielleicht bin ich dumm? Wirf ein paar Ratschläge, Leute!

Antworten:


31

Wo sollen wir die Suchaktion durchführen?

In GET /search/:text. Dies gibt ein JSON-Array mit den Übereinstimmungen zurück, wobei jede Übereinstimmung das Album enthält, zu dem sie gehört. Dies ist sinnvoll, da sich der Kunde möglicherweise nicht für den Titel selbst, sondern für das gesamte Album interessiert (stellen Sie sich vor, Sie suchen nach einem Song, der sich Ihrer Meinung nach im selben Album befindet wie der, an den Sie sich erinnern).

es wird nicht so gut sein, Eltern-IDs mit jedem so zurückzugeben. Liege ich falsch?

Einzelne Titel können das Album enthalten. Auf diese Weise wird sichergestellt, dass die Titeldarstellung einheitlich ist, wenn Sie einen Titel entweder über ein Album oder über die Suche erhalten können (hier kein Album).

Welches ist besser?

Wie bereits erwähnt, macht es Sinn, das Album einzuschließen. Während der dritte Punkt (mit der relativen URI) in einigen Fällen interessant sein kann (Sie müssen sich keine Gedanken darüber machen, wie die URI gebildet werden soll), hat er den Nachteil, dass das Album nicht explizit angegeben wird. Der vierte Punkt korrigiert dies. Wenn Sie den Vorteil sehen, den relativen URI in der Antwort zu haben, können Sie die Punkte 3 und 4 kombinieren.

Oder vielleicht bin ich dumm?

Die Auswahl guter URIs ist keine leichte Aufgabe, zumal es keine einzige richtige Antwort gibt. Wenn Sie den Client zur gleichen Zeit wie die API entwickeln, können Sie möglicherweise besser veranschaulichen, wie die API verwendet werden könnte. Abgesehen davon bevorzugen andere Benutzer möglicherweise andere Verwendungen, an die Sie bei der Entwicklung der API nicht gedacht haben.

Ein Aspekt, der problematisch sein kann, ist die interne Organisation von Daten, dh die Verwendung einer Hierarchie. In Ihrem Kommentar fragen Sie sich, worauf eine Antwort enthalten sein sollte GET /artist/1/album/10/song/3/comment/23, die eine sehr baumorientierte Vision zeigt. Dies kann zu einigen Problemen führen, wenn das System später erweitert wird. Zum Beispiel:

  • Was ist, wenn ein Song kein Album hat?
  • Was ist, wenn ein Album mehrere Künstler hat?
  • Was ist, wenn Sie eine Funktion hinzufügen möchten, mit der Sie Alben kommentieren können?
  • Was ist, wenn es Kommentare von Kommentaren geben sollte?
  • etc.

Dies ist im Wesentlichen das Problem, das ich in meinem Blog erklärt habe : Eine Baumdarstellung weist zu viele Einschränkungen auf, um in vielen Fällen effektiv verwendet zu werden.

Was passiert, wenn Sie die Hierarchie zerstören? Wir werden sehen.

  1. GET /albums/:albumIdGibt eine JSON-Datei mit den Metainformationen zum Album (z. B. das Erscheinungsjahr des Albums oder die URI des JPEG-Dokuments mit dem Album-Cover) und einer Reihe von Titeln zurück. Beispielsweise:

    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"
            }
            ...
        ]
    }

    Warum nehme ich zum Beispiel die Länge jeder Spur auf? Weil ich mir vorstelle, dass der Kunde, der ein Album zeigt, interessiert sein könnte, indem er die Titel nach Titeln auflistet, aber auch die Länge jedes Titels anzeigt - das tun die meisten Kunden. Andererseits kann es sein, dass ich nicht für jeden Titel den oder die Komponisten oder Interpreten zeige, da ich feststelle, dass diese Informationen auf dieser Ebene nicht erforderlich sind. Offensichtlich können Ihre Entscheidungen unterschiedlich sein.

  2. GET /tracks/:trackIdGibt die Informationen zu einem bestimmten Track zurück. Da es keine Hierarchie mehr gibt, müssen Sie weder das Album noch den Interpreten erraten: Das einzige, was Sie wirklich wissen müssen, ist die Bezeichnung des Tracks.

    Oder vielleicht auch nicht? Was ist, wenn Sie es mit dem Namen angeben können 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
        }
    }

    Nun schau genauer hin albums; was siehst du? Richtig, nicht eines, sondern zwei Alben. Wenn Sie eine Hierarchie haben, können Sie dies nicht tun (es sei denn, Sie duplizieren den Datensatz).

  3. GET /comments/:objectGid. Möglicherweise haben Sie die hässlichen GUIDs in den Antworten entdeckt. Mit diesen GUIDs kann die Entität in der Datenbank identifiziert werden, um Aufgaben auszuführen, die auf Alben, Interpreten oder Titel angewendet werden können. Wie zum Beispiel kommentieren.

    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"
        }
    ]

    Der Kommentar verweist auf das betreffende Objekt und ermöglicht den Zugriff auf den Kommentar außerhalb seines Kontexts (z. B. beim Moderieren der letzten Kommentare durch GET /comments/latest).

Beachten Sie, dass dies nicht bedeutet, dass Sie jede Form von Hierarchie in Ihrer API vermeiden sollten. Es gibt Fälle, in denen es Sinn macht. Als Faustregel gilt:

  • Wenn die Ressource außerhalb des Kontexts der übergeordneten Ressource keinen Sinn ergibt, verwenden Sie die Hierarchie.

  • Wenn die Ressource (1) alleine oder (2) in einem Kontext von übergeordneten Ressourcen verschiedener Typen leben kann oder (3) mehrere übergeordnete Ressourcen hat, sollte die Hierarchie nicht verwendet werden.

Beispielsweise machen Zeilen einer Datei außerhalb des Kontexts einer Datei keinen Sinn.

GET /file/:fileId

und:

GET /file/:fileId/line/:lineIndex

sind gut.


Ja, von der Suche kann ich auch die vollständigen Albuminformationen zurückgeben, es wird eine weitere Ressource darstellen - SongSearchResultich nehme an, es ist in Ordnung. Aber was ist mit URLs? Sollte ich parentIDmit jedem Objekt versehen und es als GET-Parameter oder normaler Teil der URL verwenden? Was ist, wenn ich Tiefe> 2 habe? /artist/1/album/10/song/3/comment/23- Es ist verrückt, jeden Künstler, jedes Album und jeden Song als commentObjekt anzugeben, aber ich habe gehört, es ist ein langer Weg, aber ist das nicht verdammt ?!
dt0xff

@ dt0xff: Ich habe meine Antwort bearbeitet. Ich denke, es sollte Ihnen jetzt ein klares Bild davon geben, wie die Tiefe vermieden werden kann.
Arseni Mourzenko

Ja, es ist jetzt klar, dass es viel einfacher ist, Einstiegspunkte für jede Ressource zu implementieren (mit Ausnahme von Linien oder anderen funktionalen Dingen), ohne sie per URL zum übergeordneten Element hinzuzufügen. Vielen Dank, Sie haben mich davon überzeugt, dass meine Wahl richtig war und dass "Common Approach" (wirklich viele verschachtelte Dinge, die darauf restangularaufbauen) nicht so gut ist.
dt0xff

Gute Antwort. Ich habe jedoch ein paar Einwände. "Was ist, wenn ein Album mehrere Künstler hat?" Verschiedene URIs können dieselbe Ressource identifizieren, da der URI für die binäre Beziehung -> Ressource eindeutig ist (viele-zu-eins). So können die URIs /artists/foo/albums/quxund /artists/bar/albums/quxdie gleiche Albumressource perfekt identifizieren. Mit anderen Worten stellt die Pfadkomponente in einer URI eine grafische Darstellung Hierarchie, die nicht unbedingt eine Baumhierarchie, die für die Darstellung nicht nur Kategorien , sondern auch Tags geeignet macht.
Maggyero

1
… "Dies ist im Wesentlichen das Problem, das ich in meinem Blog erklärt habe : Eine Baumdarstellung hat zu viele Einschränkungen, um in vielen Fällen effektiv verwendet zu werden." Also nein, das ist kein Problem. "Was ist, wenn Sie eine Funktion hinzufügen möchten, mit der Sie Alben kommentieren können?" Das ist kein Problem: /artists/foo/albums/qux/comments/7. "Was ist, wenn es Kommentare von Kommentaren geben sollte?" Ebenso: /artists/foo/albums/qux/song/5/comments/2/comments/8.
Maggyero
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.