417 Stimmen

Was sind bewährte Methoden für REST verschachtelte Ressourcen?

Meines Wissens nach sollte jeder einzelne Ressourcenpfad nur einen kanonischen Pfad haben. Also, in dem folgenden Beispiel, welche wären gute URL-Muster?

Nehmen wir zum Beispiel eine REST-Repräsentation von Unternehmen. In diesem hypothetischen Beispiel, besitzt jedes Unternehmen 0 oder mehr Abteilungen und jede Abteilung 0 oder mehr Mitarbeiter.

Ein Abteilung kann nicht existieren ohne ein zugehöriges Unternehmen.

Ein Mitarbeiter kann nicht existieren ohne eine zugehörige Abteilung.

Nun würde ich die natürliche Darstellung der Ressourcenmuster wie folgt finden.

  • /unternehmen Eine Sammlung von Unternehmen - Akzeptiert POST für ein neues Unternehmen. Erhalte die gesamte Sammlung.
  • /unternehmen/{unternehmensId} Ein einzelnes Unternehmen. Akzeptiert GET, PUT und DELETE
  • /unternehmen/{unternehmensId}/abteilungen Akzeptiert POST für ein neues Element. (Erstellt eine Abteilung innerhalb des Unternehmens.)
  • /unternehmen/{unternehmensId}/abteilungen/{abteilungsId}/
  • /unternehmen/{unternehmensId}/abteilungen/{abteilungsId}/mitarbeiter
  • /unternehmen/{unternehmensId}/abteilungen/{abteilungsId}/mitarbeiter/{maId}

Unter Berücksichtigung der Einschränkungen, fühlt sich jede dieser Abschnitte für mich schlüssig an, wenn auch etwas tief genestet.

Allerdings habe ich Schwierigkeiten, wenn ich alle Mitarbeiter über alle Unternehmen auflisten möchte (GET).

Das Ressourcenmuster dafür würde am ehesten zu /mitarbeiter (Die Sammlung aller Mitarbeiter) passen

Bedeutet das, dass ich auch /mitarbeiter/{maId} haben sollte, weil wenn ja, gibt es dann zwei URIs, um die gleiche Ressource abzurufen?

Oder vielleicht sollte das gesamte Schema abgeflacht werden, aber das würde bedeuten, dass Mitarbeiter ein verschachteltes Top-Level-Objekt sind.

Auf einer grundlegenden Ebene gibt /mitarbeiter/?unternehmen={unternehmensId}&abteilung={abteilungsId} die genau gleiche Ansicht der Mitarbeiter wie das am tiefsten verschachtelte Muster zurück.

Was ist die bewährte Praxis für URL-Muster, bei denen Ressourcen von anderen Ressourcen besessen werden, aber separat abgefragt werden sollen?

277voto

Patc Punkte 2811

Ich habe beide Designstrategien ausprobiert - verschachtelte und nicht-verschachtelte Endpunkte. Ich habe festgestellt, dass:

  1. wenn die verschachtelte Ressource einen Primärschlüssel hat und Sie den Primärschlüssel des übergeordneten Elements nicht haben, erfordert die verschachtelte Struktur, dass Sie diesen erhalten, obwohl das System dies tatsächlich nicht erfordert.

  2. verschachtelte Endpunkte erfordern in der Regel überflüssige Endpunkte. Mit anderen Worten, Sie benötigen in der Regel den zusätzlichen Endpunkt /employees, um eine Liste von Mitarbeitern in verschiedenen Abteilungen zu erhalten. Wenn Sie /employees haben, was bietet Ihnen dann genau /companies/departments/employees?

  3. verschachtelte Endpunkte entwickeln sich nicht so gut. Z.B. müssen Sie jetzt vielleicht nicht nach Mitarbeitern suchen, aber später vielleicht schon, und wenn Sie eine verschachtelte Struktur haben, haben Sie keine andere Wahl, als einen weiteren Endpunkt hinzuzufügen. Bei einem nicht-verschachtelten Design fügen Sie einfach weitere Parameter hinzu, was einfacher ist.

  4. manchmal kann eine Ressource mehrere Arten von übergeordneten Elementen haben. Dies führt zu mehreren Endpunkten, die alle die gleiche Ressource zurückgeben.

  5. überflüssige Endpunkte führen dazu, dass die Dokumentation schwieriger zu schreiben ist und die API auch schwieriger zu erlernen ist.

Kurz gesagt scheint das nicht-verschachtelte Design ein flexibleres und einfacheres Endpunkt-Schema zu ermöglichen.

193voto

jeremyh Punkte 5102

Was Sie getan haben, ist richtig. Im Allgemeinen können mehrere URIs auf die gleiche Ressource verweisen - es gibt keine Regeln, die besagen, dass Sie das nicht tun sollten.

Und im Allgemeinen müssen Sie möglicherweise auf Elemente direkt oder als Teilmenge von etwas anderem zugreifen - daher macht mir Ihre Struktur Sinn.

Nur weil Mitarbeiter über die Abteilung erreichbar sind:

unternehmen/{unternehmensid}/abteilung/{abteilungsnummer}/mitarbeiter

bedeutet das nicht, dass sie auch über das Unternehmen erreichbar sind:

unternehmen/{unternehmensid}/mitarbeiter

Was Mitarbeiter für dieses Unternehmen zurückgeben würde. Es kommt darauf an, was Ihr verbrauchender Client benötigt - das ist worauf Sie abzielen sollten.

Aber ich würde hoffen, dass alle URL-Handler den gleichen Back-End-Code verwenden, um die Anfragen zu erfüllen, damit Sie keinen Code duplizieren.

101voto

Wes Punkte 6177

Ich habe das, was ich gemacht habe, von der Frage in eine Antwort verschoben, wo es wahrscheinlicher ist, dass es von mehr Leuten gesehen wird.

Was ich gemacht habe, ist, die Erstellungs-Endpunkte am verschachtelten Endpunkt zu haben. Der kanonische Endpunkt zur Änderung oder Abfrage eines Elements befindet sich nicht beim verschachtelten Ressourcen.

Also in diesem Beispiel (nur Auflistung der Endpunkte, die eine Ressource ändern)

  • POST /unternehmen/ erstellt ein neues Unternehmen und gibt einen Link zum erstellten Unternehmen zurück.
  • POST /unternehmen/{unternehmensId}/abteilungen wenn eine Abteilung erstellt wird, erstellt die neue Abteilung und gibt einen Link zu /abteilungen/{abteilungsId} zurück
  • PUT /abteilungen/{abteilungsId} ändert eine Abteilung
  • POST /abteilungen/{abteilungsId}/mitarbeiter erstellt einen neuen Mitarbeiter und gibt einen Link zu /mitarbeiter/{mitarbeiterId} zurück

Es gibt also Root-Level-Ressourcen für jede der Sammlungen. Aber das Erstellen befindet sich im besitzenden Objekt.

92voto

Long Nguyen Punkte 8040

Ich habe alle oben genannten Antworten gelesen, aber es scheint, als hätten sie keine gemeinsame Strategie. Ich habe einen guten Artikel über Best Practices im Design von APIs aus Microsoft-Dokumenten gefunden. Ich denke, du solltest dich darauf beziehen.

In komplexeren Systemen kann es verlockend sein, URIs bereitzustellen, die einem Client ermöglichen, durch mehrere Ebenen von Beziehungen zu navigieren, wie z.B. /kunden/1/aufträge/99/produkte. Diese Komplexität kann jedoch schwer zu pflegen sein und ist unflexibel, wenn sich die Beziehungen zwischen Ressourcen in Zukunft ändern. Versuchen Sie stattdessen, die URIs relativ einfach zu halten. Sobald eine Anwendung eine Referenz zu einer Ressource hat, sollte es möglich sein, diese Referenz zu verwenden, um Elemente zu finden, die mit dieser Ressource zusammenhängen. Die vorherige Abfrage kann durch den URI /kunden/1/aufträge ersetzt werden, um alle Aufträge für den Kunden 1 zu finden, und dann /aufträge/99/produkte, um die Produkte in diesem Auftrag zu finden.

.

Tipp

Achten Sie darauf, dass die Ressourcen-URIs nicht komplexer sind als sammlung/eintrag/sammlung.

20voto

Maxime Laval Punkte 3808

Ich bin anderer Meinung über diese Art von Pfad

GET /Unternehmen/{UnternehmensID}/Abteilungen

Wenn Sie Abteilungen abrufen möchten, denke ich, dass es besser ist, eine Ressource /Abteilungen zu verwenden

GET /Abteilungen?UnternehmensID=123

Ich gehe davon aus, dass Sie eine Unternehmen-Tabelle und eine Abteilungen-Tabelle haben, dann Klassen, um sie in der von Ihnen verwendeten Programmiersprache zu verknüpfen. Ich gehe auch davon aus, dass Abteilungen an andere Entitäten als Unternehmen angehängt werden können, daher ist eine /Abteilungen-Ressource einfach, es ist praktisch, Ressourcen auf Tabellen abzubilden, und Sie müssen auch nicht so viele Endpunkte haben, da Sie sie wiederverwenden können

GET /Abteilungen?UnternehmensID=123

für jeden Suchvorgang, zum Beispiel

GET /Abteilungen?Name=xxx
GET /Abteilungen?UnternehmensID=123&Name=xxx
usw.

Wenn Sie eine Abteilung erstellen möchten, sollte die

POST /Abteilungen

-Ressource verwendet werden und der Anfrage-Bodysollte die Unternehmens-ID enthalten (wenn die Abteilung nur mit einem Unternehmen verknüpft werden kann).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X